RobMen: Convert build process to 100% MSBuild.

RobMen: Add sample how to call Burn with embedded progress.

RobMen: Add Bundle self-update support to Burn.

WixBuild: Version 3.7.821.0

--HG--
branch : wix37
This commit is contained in:
Rob Mensching 2012-08-21 11:36:08 -07:00
Родитель 39b1216d43
Коммит 604635b367
3850 изменённых файлов: 826436 добавлений и 2 удалений

Просмотреть файл

@ -1,3 +1,2 @@
syntax: regexp
^.*\.snt
^external
^.*\.feed

12
history.txt Normal file
Просмотреть файл

@ -0,0 +1,12 @@
WixBuild: Version 3.7.0.0
RobMen: WiX v3.7
RobMen: Convert build process to 100% MSBuild.
RobMen: Add sample how to call Burn with embedded progress.
RobMen: Add Bundle self-update support to Burn.
WixBuild: Version 3.7.0821.0

699
src/DTF.sln Normal file
Просмотреть файл

@ -0,0 +1,699 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{B217BE43-6280-4320-8477-BA0CEEFC38EE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{43C7C815-5DA4-419D-882E-34263D869897}"
ProjectSection(SolutionItems) = preProject
DTF.testrunconfig = DTF.testrunconfig
DTF.vsmdi = DTF.vsmdi
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{9A8288B8-A634-4BD3-9CC7-0F7C1314156B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Compression", "DTF\Libraries\Compression\Compression.csproj", "{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Compression.Zip", "DTF\Libraries\Compression.Zip\Compression.Zip.csproj", "{261F2857-B521-42A4-A3E0-B5165F225E50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Compression.Cab", "DTF\Libraries\Compression.Cab\Compression.Cab.csproj", "{15895FD1-DD68-407B-8717-08F6DD14F02C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInstaller", "DTF\Libraries\WindowsInstaller\WindowsInstaller.csproj", "{24121677-0ED0-41B5-833F-1B9A18E87BF4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInstaller.Linq", "DTF\Libraries\WindowsInstaller.Linq\WindowsInstaller.Linq.csproj", "{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInstaller.Package", "DTF\Libraries\WindowsInstaller.Package\WindowsInstaller.Package.csproj", "{1A9940A7-3E29-4428-B753-C4CC66058F1A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XPack", "DTF\Samples\XPack\XPack.csproj", "{03E55D95-DABE-4571-9CDA-92A44F92A465}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SfxCA", "DTF\Tools\SfxCA\SfxCA.vcxproj", "{55D5BA28-D427-4F53-80C2-FE9EF23C1553}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MakeSfxCA", "DTF\Tools\MakeSfxCA\MakeSfxCA.csproj", "{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}"
ProjectSection(ProjectDependencies) = postProject
{03E55D95-DABE-4571-9CDA-92A44F92A465} = {03E55D95-DABE-4571-9CDA-92A44F92A465}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManagedCA", "DTF\Samples\ManagedCA\ManagedCA.csproj", "{DB9E5F02-8241-440A-9B60-980EB5B42B13}"
ProjectSection(ProjectDependencies) = postProject
{55D5BA28-D427-4F53-80C2-FE9EF23C1553} = {55D5BA28-D427-4F53-80C2-FE9EF23C1553}
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B} = {3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resources", "DTF\Libraries\Resources\Resources.csproj", "{44931ECB-8D6F-4C12-A872-64E261B6A98E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory", "DTF\Samples\Inventory\Inventory.csproj", "{51480F8E-B80F-42DC-91E7-3542C1F12F8C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WiFile", "DTF\Samples\WiFile\WiFile.csproj", "{AE562F7F-EE33-41D6-A962-DA488FEFBD08}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDiff", "DTF\Samples\DDiff\DDiff.csproj", "{1CDF4242-4C00-4744-BBCD-085128978FF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedUI", "DTF\Samples\EmbeddedUI\EmbeddedUI.csproj", "{864B8C50-7895-4485-AC89-900D86FD8C0D}"
ProjectSection(ProjectDependencies) = postProject
{55D5BA28-D427-4F53-80C2-FE9EF23C1553} = {55D5BA28-D427-4F53-80C2-FE9EF23C1553}
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B} = {3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompressionTest", "DTF\Tests\Compression\CompressionTest.csproj", "{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CabTest", "DTF\Tests\Compression.Cab\CabTest.csproj", "{4544158C-2D63-4146-85FF-62169280144E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZipTest", "DTF\Tests\Compression.Zip\ZipTest.csproj", "{328799BB-7B03-4B28-8180-4132211FD07D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInstallerTest", "DTF\Tests\WindowsInstaller\WindowsInstallerTest.csproj", "{16F5202F-9276-4166-975C-C9654BAF8012}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomActionTest", "DTF\Tests\WindowsInstaller.CustomActions\CustomActionTest.csproj", "{137D376B-989F-4FEA-9A67-01D8D38CA0DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqTest", "DTF\Tests\WindowsInstaller.Linq\LinqTest.csproj", "{4F55F9B8-D8B6-41EB-8796-221B4CD98324}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = DTF.vsmdi
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|arm = Debug|arm
Debug|ia64 = Debug|ia64
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|arm = Release|arm
Release|ia64 = Release|ia64
Release|Mixed Platforms = Release|Mixed Platforms
Release|Win32 = Release|Win32
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|arm.ActiveCfg = Debug|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|arm.Build.0 = Debug|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|ia64.ActiveCfg = Debug|ia64
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|ia64.Build.0 = Debug|ia64
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Mixed Platforms.Build.0 = Debug|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Win32.ActiveCfg = Debug|Win32
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|Win32.Build.0 = Debug|Win32
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|x64.ActiveCfg = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|x64.Build.0 = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|x86.ActiveCfg = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Debug|x86.Build.0 = Debug|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Any CPU.Build.0 = Release|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|arm.ActiveCfg = Release|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|arm.Build.0 = Release|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|ia64.ActiveCfg = Release|ia64
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|ia64.Build.0 = Release|ia64
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Mixed Platforms.ActiveCfg = Release|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Mixed Platforms.Build.0 = Release|arm
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Win32.ActiveCfg = Release|Win32
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|Win32.Build.0 = Release|Win32
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|x64.ActiveCfg = Release|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|x64.Build.0 = Release|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|x86.ActiveCfg = Release|Any CPU
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}.Release|x86.Build.0 = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|arm.ActiveCfg = Debug|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|arm.Build.0 = Debug|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|ia64.ActiveCfg = Debug|ia64
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|ia64.Build.0 = Debug|ia64
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Mixed Platforms.Build.0 = Debug|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Win32.ActiveCfg = Debug|Win32
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|Win32.Build.0 = Debug|Win32
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|x64.ActiveCfg = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|x64.Build.0 = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|x86.ActiveCfg = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Debug|x86.Build.0 = Debug|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Any CPU.Build.0 = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|arm.ActiveCfg = Release|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|arm.Build.0 = Release|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|ia64.ActiveCfg = Release|ia64
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|ia64.Build.0 = Release|ia64
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Mixed Platforms.ActiveCfg = Release|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Mixed Platforms.Build.0 = Release|arm
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Win32.ActiveCfg = Release|Win32
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|Win32.Build.0 = Release|Win32
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|x64.ActiveCfg = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|x64.Build.0 = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|x86.ActiveCfg = Release|Any CPU
{261F2857-B521-42A4-A3E0-B5165F225E50}.Release|x86.Build.0 = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|arm.ActiveCfg = Debug|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|arm.Build.0 = Debug|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|ia64.ActiveCfg = Debug|ia64
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|ia64.Build.0 = Debug|ia64
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Mixed Platforms.Build.0 = Debug|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Win32.ActiveCfg = Debug|Win32
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|Win32.Build.0 = Debug|Win32
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|x64.ActiveCfg = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|x64.Build.0 = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|x86.ActiveCfg = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Debug|x86.Build.0 = Debug|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Any CPU.Build.0 = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|arm.ActiveCfg = Release|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|arm.Build.0 = Release|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|ia64.ActiveCfg = Release|ia64
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|ia64.Build.0 = Release|ia64
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Mixed Platforms.ActiveCfg = Release|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Mixed Platforms.Build.0 = Release|arm
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Win32.ActiveCfg = Release|Win32
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|Win32.Build.0 = Release|Win32
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|x64.ActiveCfg = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|x64.Build.0 = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|x86.ActiveCfg = Release|Any CPU
{15895FD1-DD68-407B-8717-08F6DD14F02C}.Release|x86.Build.0 = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|arm.ActiveCfg = Debug|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|arm.Build.0 = Debug|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|ia64.ActiveCfg = Debug|ia64
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|ia64.Build.0 = Debug|ia64
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Mixed Platforms.Build.0 = Debug|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Win32.ActiveCfg = Debug|Win32
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|Win32.Build.0 = Debug|Win32
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|x64.ActiveCfg = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|x64.Build.0 = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|x86.ActiveCfg = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Debug|x86.Build.0 = Debug|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Any CPU.Build.0 = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|arm.ActiveCfg = Release|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|arm.Build.0 = Release|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|ia64.ActiveCfg = Release|ia64
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|ia64.Build.0 = Release|ia64
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Mixed Platforms.ActiveCfg = Release|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Mixed Platforms.Build.0 = Release|arm
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Win32.ActiveCfg = Release|Win32
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|Win32.Build.0 = Release|Win32
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|x64.ActiveCfg = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|x64.Build.0 = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|x86.ActiveCfg = Release|Any CPU
{24121677-0ED0-41B5-833F-1B9A18E87BF4}.Release|x86.Build.0 = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|arm.ActiveCfg = Debug|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|arm.Build.0 = Debug|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|ia64.ActiveCfg = Debug|ia64
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|ia64.Build.0 = Debug|ia64
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Mixed Platforms.Build.0 = Debug|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Win32.ActiveCfg = Debug|Win32
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|Win32.Build.0 = Debug|Win32
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|x64.ActiveCfg = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|x64.Build.0 = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|x86.ActiveCfg = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Debug|x86.Build.0 = Debug|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Any CPU.Build.0 = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|arm.ActiveCfg = Release|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|arm.Build.0 = Release|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|ia64.ActiveCfg = Release|ia64
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|ia64.Build.0 = Release|ia64
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Mixed Platforms.ActiveCfg = Release|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Mixed Platforms.Build.0 = Release|arm
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Win32.ActiveCfg = Release|Win32
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|Win32.Build.0 = Release|Win32
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|x64.ActiveCfg = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|x64.Build.0 = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|x86.ActiveCfg = Release|Any CPU
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E}.Release|x86.Build.0 = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|arm.ActiveCfg = Debug|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|arm.Build.0 = Debug|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|ia64.ActiveCfg = Debug|ia64
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|ia64.Build.0 = Debug|ia64
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Mixed Platforms.Build.0 = Debug|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Win32.ActiveCfg = Debug|Win32
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|Win32.Build.0 = Debug|Win32
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|x64.ActiveCfg = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|x64.Build.0 = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|x86.ActiveCfg = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Debug|x86.Build.0 = Debug|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Any CPU.Build.0 = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|arm.ActiveCfg = Release|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|arm.Build.0 = Release|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|ia64.ActiveCfg = Release|ia64
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|ia64.Build.0 = Release|ia64
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Mixed Platforms.ActiveCfg = Release|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Mixed Platforms.Build.0 = Release|arm
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Win32.ActiveCfg = Release|Win32
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|Win32.Build.0 = Release|Win32
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|x64.ActiveCfg = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|x64.Build.0 = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|x86.ActiveCfg = Release|Any CPU
{1A9940A7-3E29-4428-B753-C4CC66058F1A}.Release|x86.Build.0 = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|arm.ActiveCfg = Debug|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|arm.Build.0 = Debug|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|ia64.ActiveCfg = Debug|ia64
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|ia64.Build.0 = Debug|ia64
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Mixed Platforms.Build.0 = Debug|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Win32.ActiveCfg = Debug|Win32
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|Win32.Build.0 = Debug|Win32
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|x64.ActiveCfg = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|x64.Build.0 = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|x86.ActiveCfg = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Debug|x86.Build.0 = Debug|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Any CPU.Build.0 = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|arm.ActiveCfg = Release|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|arm.Build.0 = Release|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|ia64.ActiveCfg = Release|ia64
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|ia64.Build.0 = Release|ia64
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Mixed Platforms.ActiveCfg = Release|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Mixed Platforms.Build.0 = Release|arm
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Win32.ActiveCfg = Release|Win32
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|Win32.Build.0 = Release|Win32
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|x64.ActiveCfg = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|x64.Build.0 = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|x86.ActiveCfg = Release|Any CPU
{03E55D95-DABE-4571-9CDA-92A44F92A465}.Release|x86.Build.0 = Release|Any CPU
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|Any CPU.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|arm.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|ia64.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|Win32.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|Win32.Build.0 = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|x64.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|x86.ActiveCfg = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Debug|x86.Build.0 = Debug|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|Any CPU.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|arm.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|ia64.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|Mixed Platforms.Build.0 = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|Win32.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|Win32.Build.0 = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|x64.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|x86.ActiveCfg = Release|Win32
{55D5BA28-D427-4F53-80C2-FE9EF23C1553}.Release|x86.Build.0 = Release|Win32
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|arm.ActiveCfg = Debug|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|arm.Build.0 = Debug|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|ia64.ActiveCfg = Debug|ia64
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|ia64.Build.0 = Debug|ia64
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Mixed Platforms.Build.0 = Debug|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Win32.ActiveCfg = Debug|Win32
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|Win32.Build.0 = Debug|Win32
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|x64.ActiveCfg = Debug|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|x64.Build.0 = Debug|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|x86.ActiveCfg = Debug|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Debug|x86.Build.0 = Debug|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Any CPU.Build.0 = Release|Any CPU
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|arm.ActiveCfg = Release|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|arm.Build.0 = Release|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|ia64.ActiveCfg = Release|ia64
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|ia64.Build.0 = Release|ia64
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Mixed Platforms.ActiveCfg = Release|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Mixed Platforms.Build.0 = Release|arm
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Win32.ActiveCfg = Release|Win32
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|Win32.Build.0 = Release|Win32
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|x64.ActiveCfg = Release|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|x64.Build.0 = Release|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|x86.ActiveCfg = Release|x86
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B}.Release|x86.Build.0 = Release|x86
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|arm.ActiveCfg = Debug|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|arm.Build.0 = Debug|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|ia64.ActiveCfg = Debug|ia64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|ia64.Build.0 = Debug|ia64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Mixed Platforms.Build.0 = Debug|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Win32.ActiveCfg = Debug|Win32
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|Win32.Build.0 = Debug|Win32
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|x64.ActiveCfg = Debug|x64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|x64.Build.0 = Debug|x64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|x86.ActiveCfg = Debug|x86
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Debug|x86.Build.0 = Debug|x86
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Any CPU.Build.0 = Release|Any CPU
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|arm.ActiveCfg = Release|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|arm.Build.0 = Release|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|ia64.ActiveCfg = Release|ia64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|ia64.Build.0 = Release|ia64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Mixed Platforms.ActiveCfg = Release|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Mixed Platforms.Build.0 = Release|arm
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Win32.ActiveCfg = Release|Win32
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|Win32.Build.0 = Release|Win32
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|x64.ActiveCfg = Release|x64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|x64.Build.0 = Release|x64
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|x86.ActiveCfg = Release|x86
{DB9E5F02-8241-440A-9B60-980EB5B42B13}.Release|x86.Build.0 = Release|x86
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|arm.ActiveCfg = Debug|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|arm.Build.0 = Debug|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|ia64.ActiveCfg = Debug|ia64
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|ia64.Build.0 = Debug|ia64
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Mixed Platforms.Build.0 = Debug|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Win32.ActiveCfg = Debug|Win32
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|Win32.Build.0 = Debug|Win32
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|x64.ActiveCfg = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|x64.Build.0 = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|x86.ActiveCfg = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Debug|x86.Build.0 = Debug|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Any CPU.Build.0 = Release|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|arm.ActiveCfg = Release|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|arm.Build.0 = Release|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|ia64.ActiveCfg = Release|ia64
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|ia64.Build.0 = Release|ia64
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Mixed Platforms.ActiveCfg = Release|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Mixed Platforms.Build.0 = Release|arm
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Win32.ActiveCfg = Release|Win32
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|Win32.Build.0 = Release|Win32
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|x64.ActiveCfg = Release|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|x64.Build.0 = Release|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|x86.ActiveCfg = Release|Any CPU
{44931ECB-8D6F-4C12-A872-64E261B6A98E}.Release|x86.Build.0 = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|arm.ActiveCfg = Debug|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|arm.Build.0 = Debug|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|ia64.ActiveCfg = Debug|ia64
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|ia64.Build.0 = Debug|ia64
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Mixed Platforms.Build.0 = Debug|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Win32.ActiveCfg = Debug|Win32
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|Win32.Build.0 = Debug|Win32
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|x64.ActiveCfg = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|x64.Build.0 = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|x86.ActiveCfg = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Debug|x86.Build.0 = Debug|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Any CPU.Build.0 = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|arm.ActiveCfg = Release|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|arm.Build.0 = Release|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|ia64.ActiveCfg = Release|ia64
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|ia64.Build.0 = Release|ia64
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Mixed Platforms.ActiveCfg = Release|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Mixed Platforms.Build.0 = Release|arm
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Win32.ActiveCfg = Release|Win32
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|Win32.Build.0 = Release|Win32
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|x64.ActiveCfg = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|x64.Build.0 = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|x86.ActiveCfg = Release|Any CPU
{51480F8E-B80F-42DC-91E7-3542C1F12F8C}.Release|x86.Build.0 = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|arm.ActiveCfg = Debug|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|arm.Build.0 = Debug|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|ia64.ActiveCfg = Debug|ia64
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|ia64.Build.0 = Debug|ia64
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Mixed Platforms.Build.0 = Debug|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Win32.ActiveCfg = Debug|Win32
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|Win32.Build.0 = Debug|Win32
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|x64.ActiveCfg = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|x64.Build.0 = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|x86.ActiveCfg = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Debug|x86.Build.0 = Debug|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Any CPU.Build.0 = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|arm.ActiveCfg = Release|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|arm.Build.0 = Release|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|ia64.ActiveCfg = Release|ia64
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|ia64.Build.0 = Release|ia64
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Mixed Platforms.ActiveCfg = Release|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Mixed Platforms.Build.0 = Release|arm
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Win32.ActiveCfg = Release|Win32
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|Win32.Build.0 = Release|Win32
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|x64.ActiveCfg = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|x64.Build.0 = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|x86.ActiveCfg = Release|Any CPU
{AE562F7F-EE33-41D6-A962-DA488FEFBD08}.Release|x86.Build.0 = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|arm.ActiveCfg = Debug|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|arm.Build.0 = Debug|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|ia64.ActiveCfg = Debug|ia64
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|ia64.Build.0 = Debug|ia64
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Mixed Platforms.Build.0 = Debug|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Win32.ActiveCfg = Debug|Win32
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|Win32.Build.0 = Debug|Win32
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|x64.ActiveCfg = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|x64.Build.0 = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|x86.ActiveCfg = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Debug|x86.Build.0 = Debug|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Any CPU.Build.0 = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|arm.ActiveCfg = Release|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|arm.Build.0 = Release|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|ia64.ActiveCfg = Release|ia64
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|ia64.Build.0 = Release|ia64
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Mixed Platforms.ActiveCfg = Release|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Mixed Platforms.Build.0 = Release|arm
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Win32.ActiveCfg = Release|Win32
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|Win32.Build.0 = Release|Win32
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|x64.ActiveCfg = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|x64.Build.0 = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|x86.ActiveCfg = Release|Any CPU
{1CDF4242-4C00-4744-BBCD-085128978FF3}.Release|x86.Build.0 = Release|Any CPU
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|arm.ActiveCfg = Debug|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|arm.Build.0 = Debug|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|ia64.ActiveCfg = Debug|ia64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|ia64.Build.0 = Debug|ia64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Mixed Platforms.Build.0 = Debug|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Win32.ActiveCfg = Debug|Win32
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|Win32.Build.0 = Debug|Win32
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|x64.ActiveCfg = Debug|x64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|x64.Build.0 = Debug|x64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|x86.ActiveCfg = Debug|x86
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Debug|x86.Build.0 = Debug|x86
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Any CPU.Build.0 = Release|Any CPU
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|arm.ActiveCfg = Release|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|arm.Build.0 = Release|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|ia64.ActiveCfg = Release|ia64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|ia64.Build.0 = Release|ia64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Mixed Platforms.ActiveCfg = Release|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Mixed Platforms.Build.0 = Release|arm
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Win32.ActiveCfg = Release|Win32
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|Win32.Build.0 = Release|Win32
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|x64.ActiveCfg = Release|x64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|x64.Build.0 = Release|x64
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|x86.ActiveCfg = Release|x86
{864B8C50-7895-4485-AC89-900D86FD8C0D}.Release|x86.Build.0 = Release|x86
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|arm.ActiveCfg = Debug|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|arm.Build.0 = Debug|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|ia64.ActiveCfg = Debug|ia64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|ia64.Build.0 = Debug|ia64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Mixed Platforms.Build.0 = Debug|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Win32.ActiveCfg = Debug|Win32
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|Win32.Build.0 = Debug|Win32
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|x64.ActiveCfg = Debug|x64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|x64.Build.0 = Debug|x64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|x86.ActiveCfg = Debug|x86
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Debug|x86.Build.0 = Debug|x86
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Any CPU.Build.0 = Release|Any CPU
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|arm.ActiveCfg = Release|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|arm.Build.0 = Release|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|ia64.ActiveCfg = Release|ia64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|ia64.Build.0 = Release|ia64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Mixed Platforms.ActiveCfg = Release|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Mixed Platforms.Build.0 = Release|arm
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Win32.ActiveCfg = Release|Win32
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|Win32.Build.0 = Release|Win32
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|x64.ActiveCfg = Release|x64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|x64.Build.0 = Release|x64
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|x86.ActiveCfg = Release|x86
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9}.Release|x86.Build.0 = Release|x86
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4544158C-2D63-4146-85FF-62169280144E}.Debug|arm.ActiveCfg = Debug|arm
{4544158C-2D63-4146-85FF-62169280144E}.Debug|arm.Build.0 = Debug|arm
{4544158C-2D63-4146-85FF-62169280144E}.Debug|ia64.ActiveCfg = Debug|ia64
{4544158C-2D63-4146-85FF-62169280144E}.Debug|ia64.Build.0 = Debug|ia64
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Mixed Platforms.Build.0 = Debug|arm
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Win32.ActiveCfg = Debug|Win32
{4544158C-2D63-4146-85FF-62169280144E}.Debug|Win32.Build.0 = Debug|Win32
{4544158C-2D63-4146-85FF-62169280144E}.Debug|x64.ActiveCfg = Debug|x64
{4544158C-2D63-4146-85FF-62169280144E}.Debug|x64.Build.0 = Debug|x64
{4544158C-2D63-4146-85FF-62169280144E}.Debug|x86.ActiveCfg = Debug|x86
{4544158C-2D63-4146-85FF-62169280144E}.Debug|x86.Build.0 = Debug|x86
{4544158C-2D63-4146-85FF-62169280144E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4544158C-2D63-4146-85FF-62169280144E}.Release|Any CPU.Build.0 = Release|Any CPU
{4544158C-2D63-4146-85FF-62169280144E}.Release|arm.ActiveCfg = Release|arm
{4544158C-2D63-4146-85FF-62169280144E}.Release|arm.Build.0 = Release|arm
{4544158C-2D63-4146-85FF-62169280144E}.Release|ia64.ActiveCfg = Release|ia64
{4544158C-2D63-4146-85FF-62169280144E}.Release|ia64.Build.0 = Release|ia64
{4544158C-2D63-4146-85FF-62169280144E}.Release|Mixed Platforms.ActiveCfg = Release|arm
{4544158C-2D63-4146-85FF-62169280144E}.Release|Mixed Platforms.Build.0 = Release|arm
{4544158C-2D63-4146-85FF-62169280144E}.Release|Win32.ActiveCfg = Release|Win32
{4544158C-2D63-4146-85FF-62169280144E}.Release|Win32.Build.0 = Release|Win32
{4544158C-2D63-4146-85FF-62169280144E}.Release|x64.ActiveCfg = Release|x64
{4544158C-2D63-4146-85FF-62169280144E}.Release|x64.Build.0 = Release|x64
{4544158C-2D63-4146-85FF-62169280144E}.Release|x86.ActiveCfg = Release|x86
{4544158C-2D63-4146-85FF-62169280144E}.Release|x86.Build.0 = Release|x86
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|arm.ActiveCfg = Debug|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|arm.Build.0 = Debug|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|ia64.ActiveCfg = Debug|ia64
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|ia64.Build.0 = Debug|ia64
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Mixed Platforms.Build.0 = Debug|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Win32.ActiveCfg = Debug|Win32
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|Win32.Build.0 = Debug|Win32
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|x64.ActiveCfg = Debug|x64
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|x64.Build.0 = Debug|x64
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|x86.ActiveCfg = Debug|x86
{328799BB-7B03-4B28-8180-4132211FD07D}.Debug|x86.Build.0 = Debug|x86
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Any CPU.Build.0 = Release|Any CPU
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|arm.ActiveCfg = Release|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|arm.Build.0 = Release|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|ia64.ActiveCfg = Release|ia64
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|ia64.Build.0 = Release|ia64
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Mixed Platforms.ActiveCfg = Release|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Mixed Platforms.Build.0 = Release|arm
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Win32.ActiveCfg = Release|Win32
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|Win32.Build.0 = Release|Win32
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|x64.ActiveCfg = Release|x64
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|x64.Build.0 = Release|x64
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|x86.ActiveCfg = Release|x86
{328799BB-7B03-4B28-8180-4132211FD07D}.Release|x86.Build.0 = Release|x86
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|arm.ActiveCfg = Debug|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|arm.Build.0 = Debug|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|ia64.ActiveCfg = Debug|ia64
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|ia64.Build.0 = Debug|ia64
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Mixed Platforms.Build.0 = Debug|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Win32.ActiveCfg = Debug|Win32
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|Win32.Build.0 = Debug|Win32
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|x64.ActiveCfg = Debug|x64
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|x64.Build.0 = Debug|x64
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|x86.ActiveCfg = Debug|x86
{16F5202F-9276-4166-975C-C9654BAF8012}.Debug|x86.Build.0 = Debug|x86
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Any CPU.Build.0 = Release|Any CPU
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|arm.ActiveCfg = Release|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|arm.Build.0 = Release|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|ia64.ActiveCfg = Release|ia64
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|ia64.Build.0 = Release|ia64
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Mixed Platforms.ActiveCfg = Release|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Mixed Platforms.Build.0 = Release|arm
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Win32.ActiveCfg = Release|Win32
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|Win32.Build.0 = Release|Win32
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|x64.ActiveCfg = Release|x64
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|x64.Build.0 = Release|x64
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|x86.ActiveCfg = Release|x86
{16F5202F-9276-4166-975C-C9654BAF8012}.Release|x86.Build.0 = Release|x86
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|arm.ActiveCfg = Debug|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|arm.Build.0 = Debug|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|ia64.ActiveCfg = Debug|ia64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|ia64.Build.0 = Debug|ia64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Mixed Platforms.Build.0 = Debug|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Win32.ActiveCfg = Debug|Win32
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|Win32.Build.0 = Debug|Win32
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|x64.ActiveCfg = Debug|x64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|x64.Build.0 = Debug|x64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|x86.ActiveCfg = Debug|x86
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Debug|x86.Build.0 = Debug|x86
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Any CPU.Build.0 = Release|Any CPU
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|arm.ActiveCfg = Release|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|arm.Build.0 = Release|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|ia64.ActiveCfg = Release|ia64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|ia64.Build.0 = Release|ia64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Mixed Platforms.ActiveCfg = Release|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Mixed Platforms.Build.0 = Release|arm
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Win32.ActiveCfg = Release|Win32
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|Win32.Build.0 = Release|Win32
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|x64.ActiveCfg = Release|x64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|x64.Build.0 = Release|x64
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|x86.ActiveCfg = Release|x86
{137D376B-989F-4FEA-9A67-01D8D38CA0DE}.Release|x86.Build.0 = Release|x86
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|arm.ActiveCfg = Debug|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|arm.Build.0 = Debug|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|ia64.ActiveCfg = Debug|ia64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|ia64.Build.0 = Debug|ia64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Mixed Platforms.ActiveCfg = Debug|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Mixed Platforms.Build.0 = Debug|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Win32.ActiveCfg = Debug|Win32
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|Win32.Build.0 = Debug|Win32
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|x64.ActiveCfg = Debug|x64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|x64.Build.0 = Debug|x64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|x86.ActiveCfg = Debug|x86
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Debug|x86.Build.0 = Debug|x86
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Any CPU.Build.0 = Release|Any CPU
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|arm.ActiveCfg = Release|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|arm.Build.0 = Release|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|ia64.ActiveCfg = Release|ia64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|ia64.Build.0 = Release|ia64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Mixed Platforms.ActiveCfg = Release|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Mixed Platforms.Build.0 = Release|arm
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Win32.ActiveCfg = Release|Win32
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|Win32.Build.0 = Release|Win32
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|x64.ActiveCfg = Release|x64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|x64.Build.0 = Release|x64
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|x86.ActiveCfg = Release|x86
{4F55F9B8-D8B6-41EB-8796-221B4CD98324}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2D62850C-9F81-4BE9-BDF3-9379389C8F7B} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{261F2857-B521-42A4-A3E0-B5165F225E50} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{15895FD1-DD68-407B-8717-08F6DD14F02C} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{24121677-0ED0-41B5-833F-1B9A18E87BF4} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{CD7A37D8-9D8C-41BD-B78F-DB5E0C299D2E} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{1A9940A7-3E29-4428-B753-C4CC66058F1A} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{44931ECB-8D6F-4C12-A872-64E261B6A98E} = {B217BE43-6280-4320-8477-BA0CEEFC38EE}
{03E55D95-DABE-4571-9CDA-92A44F92A465} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{DB9E5F02-8241-440A-9B60-980EB5B42B13} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{51480F8E-B80F-42DC-91E7-3542C1F12F8C} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{AE562F7F-EE33-41D6-A962-DA488FEFBD08} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{1CDF4242-4C00-4744-BBCD-085128978FF3} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{864B8C50-7895-4485-AC89-900D86FD8C0D} = {AED0B145-6A3A-40DF-89AC-E5728B9B3DAA}
{55D5BA28-D427-4F53-80C2-FE9EF23C1553} = {9A8288B8-A634-4BD3-9CC7-0F7C1314156B}
{3F246CE0-153D-4AC3-B6AC-5EAD8E2AD04B} = {9A8288B8-A634-4BD3-9CC7-0F7C1314156B}
{F045FFC1-05F9-4EA2-9F03-E1CBDB7BC4F9} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
{4544158C-2D63-4146-85FF-62169280144E} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
{328799BB-7B03-4B28-8180-4132211FD07D} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
{16F5202F-9276-4166-975C-C9654BAF8012} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
{137D376B-989F-4FEA-9A67-01D8D38CA0DE} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
{4F55F9B8-D8B6-41EB-8796-221B4CD98324} = {8477AF4C-B4CA-4434-A6C4-9CC57C74AF21}
EndGlobalSection
EndGlobal

18
src/DTF.testrunconfig Normal file
Просмотреть файл

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<TestRunConfiguration name="Local Test Run" id="d7cdca3d-88a0-4e00-be96-2a5ca2db8548" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>This is a default test run configuration for a local test run.</Description>
<NamingScheme baseName="DTF" useDefault="false" />
<TestTypeSpecific>
<WebTestRunConfiguration testTypeId="4e7599fa-5ecb-43e9-a887-cd63cf72d207">
<Browser name="Internet Explorer 7.0">
<Headers>
<Header name="User-Agent" value="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" />
<Header name="Accept" value="*/*" />
<Header name="Accept-Language" value="{{$IEAcceptLanguage}}" />
<Header name="Accept-Encoding" value="GZIP" />
</Headers>
</Browser>
<Network Name="LAN" BandwidthInKbps="0" />
</WebTestRunConfiguration>
</TestTypeSpecific>
</TestRunConfiguration>

95
src/DTF.vsmdi Normal file
Просмотреть файл

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestList name="CA" id="687d36d6-8130-4b57-a944-cff8ee025283" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="16d12a90-2e64-c4f7-78d7-beefe14ec4ed" name="CustomActionTest1" storage="..\..\build\debug\x86\microsoft.deployment.test.customactions.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="165a9deb-4327-a539-10ed-2c60006fd719" name="CustomActionData" storage="..\..\build\debug\x86\microsoft.deployment.test.customactions.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<RunConfiguration id="d7cdca3d-88a0-4e00-be96-2a5ca2db8548" name="Local Test Run" storage="DTF.testrunconfig" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, PublicKeyToken=b03f5f7f11d50a3a" />
</TestList>
<TestList name="Linq" id="96e9fb57-2f47-4636-a194-cddc34d1b889" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="ee2ffbce-2ed4-5b54-58cc-dd8a8119640b" name="EnumProducts" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="9490b03f-2278-1311-6376-01046c6f3abf" name="EnumTable" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a8ca208b-1f65-30a2-df36-7382af157385" name="LinqWhereOperators" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e74de56a-0b83-64e2-3679-50ac37c44445" name="LinqShapeSelect" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="6ef38409-9e03-8140-bb99-dadd8a666911" name="LinqUpdateNullableString" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="94fadde8-f57f-ea1a-df6f-d3b4bad6c043" name="LinqSimple" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d92a1daa-8677-8f6f-6a12-e46ff10b2eee" name="LinqTwoWayJoin" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="fb6c62ce-c41b-d6e8-8ccc-db7dabc8ca98" name="LinqInsertDelete" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b2234eee-356b-0dc4-2e46-76887c2df8e7" name="LinqWhereNull" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="be389146-a45d-d020-49fa-c11fc0cc364d" name="EnumComponents" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="22487991-e127-15c0-fbb0-56059c1c3e87" name="LinqFourWayJoin" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ba4ab21d-81f9-fdfd-e984-ecf6c3f3a98d" name="DatabaseAsQueryable" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b3d1c4f4-6907-d08f-dc44-0c3f8e5ff7d1" name="EnumFeatures" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="35dc2cd8-35c4-96d9-441d-978f14ae0f60" name="LinqQueryQRecord" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b2b7a3a7-61f4-9f73-8bf9-71b5205c866d" name="LinqOrderBy" storage="..\..\build\debug\x86\microsoft.deployment.test.linq.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="WindowsInstaller" id="a05a5433-b0eb-4727-bee5-43ddb4dab92b" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="76e05ce1-3152-ef40-728d-8caf1ddd7fd0" name="InstallerMessageResources" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="54133410-e02d-9458-43aa-9ce8cc5e19be" name="InstallerTransactTwoProducts" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="16b75d3a-3c0b-d246-de97-8f807f9647b3" name="EnumComponentQualifiers" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="2fe64e6f-1fff-9c88-75c8-868dd92c566f" name="InstallerErrorMessages" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ba10b6f6-ff8e-8e5c-6616-193e1a450614" name="InstallerInstallProduct" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a3d56994-6796-fe9d-cca5-7270ae4fd082" name="InstallerDatabaseSchema" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a90a5a27-5eec-e305-81ce-018c9e4561e0" name="InstallerViewTables" storage="..\..\build\debug\x86\microsoft.deployment.test.windowsinstaller.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Zip" id="c0ae4f55-ac18-4545-a2a8-d5d99bc486d0" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="f5d3cd03-734c-a799-70c0-718742923d39" name="ZipInfoNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="9f3ec33c-e19b-7a69-c2f5-bf512ee2ad6c" name="ZipBadUnpackStreamContexts" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b9401275-c907-b88d-e3a7-8d41dfdb2fbb" name="ZipFileCounts" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="86f6bced-7259-ea95-c8b0-3a5355fb344b" name="ZipBadPackStreamContexts" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ccec862a-8f0e-f3d4-4655-232e8610c530" name="ZipProgress" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="8dabaf4c-b4e5-6345-a18d-e8d1ea2ae357" name="ZipFileSizes" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="7a119869-9aac-f58d-116b-3f3082704a38" name="ZipArchiveCounts" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="77c27be9-7e2a-d92f-6d57-b73576f069ae" name="ZipTruncatedArchive" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1a4cfad0-0518-a918-ce75-e97e888d38e5" name="ZipFileInfoNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1a39c6e0-57c4-3d44-9f4a-1654397ab0cd" name="ZipArchiveSizes" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="758bfad5-9240-932d-62d0-7143b9f65520" name="ZipEngineNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="8934309a-f963-832e-bbe9-27116af154cb" name="ZipCompLevelParam" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="6cd000ea-a9d8-013a-c7b7-cfa353824ac7" name="ZipInfoGetFiles" storage="..\..\build\debug\x86\microsoft.deployment.test.zip.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Cab" id="ca4dd201-739c-4cf9-bf02-5400a266accb" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="ad321d35-d261-7507-e869-b2be56cc01cb" name="CabCompLevelParam" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="fd7538ab-d8ef-587d-0b31-14c74f7ed5e1" name="CabFileInfoNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="96f42e97-11f7-bd7f-adf4-924462d699ed" name="CabinetFolders" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="2f700617-94e1-aab4-a353-6d0bf5af3df0" name="CabEngineNoTempFileTest" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="858d7183-ac3a-8994-48fc-fce87dfe58de" name="CabArchiveSizeParam" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b89ea4de-fc4c-1ddb-947e-337588a86e7f" name="CabinetBuggyFileSizes" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d6560a5f-7c8c-592b-3413-95043dc6f306" name="CabinetTruncateOnCreate" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="50656de7-a2f1-e0a3-c25b-5efa750d1041" name="CabInfoProperties" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="6cf7d53c-31cd-9ba3-305e-fbc0b24fe914" name="CabinetOffset" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="89c90096-5405-a8ed-41ab-ef40209f4976" name="CabinetArchiveCounts" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ba9a99ad-d25e-861e-fdd9-442863074848" name="CabinetExtractUpdate" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="67e07a8d-0d2f-a350-11f2-7707a258b791" name="CabInfoNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="787927f7-d237-cde5-64a8-b9025a927e3b" name="CabinetProgress" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1d6fa553-cc95-6b11-0ec8-e7784a84d693" name="CabEngineNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b536d2e8-6522-8d56-d920-69e9b963ed08" name="CabInfoGetFiles" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e0366263-19ae-c21a-4cfb-3be2399793fe" name="CabinetFileSizes" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="11c8910e-db9e-6c80-32ed-61a1ecced74b" name="CabFileStreamContextNullParams" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="50da9591-721b-9aaf-6122-82e722fa12b8" name="CabExtractorIsCabinet" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="8504adf0-98fa-c3b0-a43c-2d739104e077" name="CabFileInfoOpenText" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="c44b1f2f-ede1-ade9-8d7e-0375efebbba9" name="CabBadUnpackStreamContexts" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="4f8c2ce6-d7dd-7fe9-c04f-141220dbe342" name="CabFolderSizeParam" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e3291f3b-ef47-0195-d78d-59bbbeb33880" name="CabTruncatedArchive" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b85217ba-ce04-7d22-32ca-8f98327f2f0c" name="CabInfoCompressExtract" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e1bd864e-aa68-eb07-75a8-3ddfd1e692fe" name="CabinetUtfPaths" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="16d3fa74-8482-5ee6-a64b-24ea9d1e6799" name="CabExtractorGetFiles" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="46d4e0aa-bb0e-5f5e-e6b5-9c369dc0fefc" name="CabExtractorExtract" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="6ba757f2-a274-7aa7-72fe-392d647e2e85" name="CabExtractorFindOffset" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d5dc5ace-8708-276a-cde7-7975552c9362" name="CabFileInfoProperties" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a0f2a55c-c712-8ad4-9e81-986ec0796802" name="CabinetMultithread" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="11c8c8a0-cdb6-22ba-2715-02c7fb6c04ec" name="CabBadPackStreamContexts" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="56cf2946-b9f0-1526-2e49-425fc3f699a9" name="CabInfoSerialization" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="b694e515-8bd6-5bf8-bb8a-5d66cd299e5b" name="CabinetFileCounts" storage="..\..\build\debug\x86\microsoft.deployment.test.cab.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
</TestLists>

Просмотреть файл

@ -0,0 +1,59 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Deployment Tools Foundation Overview</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Deployment Tools Foundation</span><br />
<div id="toolbar">
<span id="chickenFeet"><span class="nolink">Overview</span></span>
<span id="languageFilter">v4.0</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>Deployment Tools Foundation is a rich set of .NET class libraries and
related resources that together bring the Windows deployment platform
technologies into the .NET world. It is designed to greatly simplify
deployment-related development tasks while still exposing the complete
functionality of the underlying technology.</p>
<p>The primary focus of DTF is to provide a foundation for development of
various kinds of tools to support deployment throughout the product
lifecycle, including setup authoring, building, analysis, debugging, and
testing tools. In addition to tools, DTF can also be useful for install-time
activities such as setup bootstrappers, external UI, and custom actions,
and for application run-time activities that need to access the deployment
platform.</p>
<p>For a description of the the latest changes, see <a
href="whatsnew.htm">What's New</a>.</p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,94 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Building Managed Custom Actions</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Building Managed Custom Actions</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<span class="nolink">Building</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>The build process for managed CA DLLs is a little complicated becuase of the
proxy-wrapper and dll-export requirements. Here's an overview:</p>
<ol>
<li>
<p>Compile your CA assembly, which references Microsoft.Deployment.WindowsInstaller.dll and
marks exported custom actions with a CustomActionAttribute.</p>
<li>
<p>Package the CA assembly, CustomAction.config, Microsoft.Deployment.WindowsInstaller.dll,
and any other dependencies using <b>MakeSfxCA.exe</b>. The filenames of CustomAction.config
and Microsoft.Deployment.WindowsInstaller.dll must not be changed, since
the custom action proxy specifically looks for those files.</p>
</ol>
<p><br>
</p>
<p><b>Compiling</b></p>
<pre><font face="Consolas, Courier New">
csc.exe
/target:library
/r:$(DTFbin)\Microsoft.Deployment.WindowsInstaller.dll
/out:SampleCAs.dll
*.cs
</font></pre>
<p><b>Wrapping</b><pre><font face="Consolas, Courier New">
MakeSfxCA.exe
$(OutDir)\SampleCAsPackage.dll
$(DTFbin)\SfxCA.dll
SampleCAs.dll
CustomAction.config
$(DTFbin)\Microsoft.Deployment.WindowsInstaller.dll
</font></pre>
</p>
<p>Now the resulting package, SampleCAsPackage.dll, is ready to be inserted
into the Binary table of the MSI.</p>
<p><br/>
</p>
<p>For a working example of building a managed custom action package
you can look at included sample ManagedCAs project.</p>
<p><br/>
</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="caconfig.htm">Specifying the Runtime Version</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,63 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Archive Pack/Unpack Tool</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Archive Pack/Unpack Tool</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="samples.htm">Samples</a> &gt;
<span class="nolink">XPack</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p><pre><font face="Consolas, Courier New">Usage: CabPack.exe &lt;directory&gt; &lt;package.cab&gt;
Usage: XPack /P &lt;archive.cab&gt; &lt;directory&gt;
Usage: XPack /P &lt;archive.zip&gt; &lt;directory&gt;
Packs all files in a directory tree into an archive,
using either the cab or zip format. Any existing archive
with the same name will be overwritten.
Usage: XPack /U &lt;archive.cab&gt; &lt;directory&gt;
Usage: XPack /U &lt;archive.zip&gt; &lt;directory&gt;
Unpacks all files from a cab or zip archive to the
specified directory. Any existing files with the same
names will be overwritten.</font></pre>
</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,101 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Working with Cabinet Files</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Working with Cabinet Files</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<span class="nolink">Cabinet Files</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h3>Creating a cabinet</h3>
<pre><font face="Consolas, Courier New"> CabInfo cabInfo = <font color="blue">new</font> CabInfo(<font color="purple">"package.cab"</font>);
cabInfo.Pack(<font color="purple">"D:\\FilesToCompress"</font>);</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_Compression_Cab_CabInfo__ctor_1.htm">new CabInfo</a> instance referring to the (future) location of the .cab file.</p>
<p>2.&nbsp; Compress files:</p><ul>
<li>Easily compress an entire directory with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_Pack.htm">Pack</a> method.</li>
<li>Compress a specific list of exernal and internal filenames with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_PackFiles.htm">PackFiles</a> method.</li>
<li>Compress a dictionary mapping of internal to external filenames with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_PackFileSet.htm">PackFileSet</a> method.</li>
</ul>
<p><br/></p>
<h3>Listing a cabinet</h3>
<pre><font face="Consolas, Courier New"> CabInfo cabInfo = <font color="blue">new</font> CabInfo(<font color="purple">"package.cab"</font>);
<font color="blue">foreach</font> (CabFileInfo fileInfo <font color="blue">in</font> cabInfo.GetFiles())
Console.WriteLine(fileInfo.Name + <font color="purple">"\t"</font> + fileInfo.Length);</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_Compression_Cab_CabInfo__ctor_1.htm">new CabInfo</a> instance referring to the location of the .cab file.</p>
<p>2.&nbsp; Enumerate files returned by the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_Cab_CabInfo_GetFiles.htm">GetFiles</a> method.</p><ul>
<li>Each <a href="DTFAPI.chm::/html/T_Microsoft_Deployment_Compression_Cab_CabFileInfo.htm">CabFileInfo</a> instance contains metadata about one file.</li>
</ul>
<p><br/></p>
<h3>Extracting a cabinet</h3>
<pre><font face="Consolas, Courier New"> CabInfo cabInfo = <font color="blue">new</font> CabInfo(<font color="purple">"package.cab"</font>);
cabInfo.Unpack(<font color="purple">"D:\\ExtractedFiles"</font>);</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_Compression_Cab_CabInfo__ctor_1.htm">new CabInfo</a> instance referring to the location of the .cab file.</p>
<p>2.&nbsp; Extract files:</p><ul>
<li>Easily extract all files to a directory with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_Unpack.htm">Unpack</a> method.</li>
<li>Easily extract a single file with the <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_Compression_ArchiveInfo_UnpackFile.htm">UnpackFile</a> method.</li>
<li>Extract a specific list of filenames with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_UnpackFiles.htm">UnpackFiles</a> method.</li>
<li>Extract a dictionary mapping of internal to external filenames with the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_Compression_ArchiveInfo_UnpackFileSet.htm">UnpackFileSet</a> method.</li>
</ul>
<p><br/></p>
<h3>Getting progress</h3>
Most cabinet operation methods have an overload that allows you to specify a event handler
for receiving <a href="DTFAPI.chm::/html/T_Microsoft_Deployment_Compression_ArchiveProgressEventArgs.htm">archive
progress events</a>. The <a href="cabpack.htm">XPack sample</a>
demonstrates use of the callback to report detailed progress to the console.
<p><br/></p>
<h3>Stream-based compression</h3>
The CabEngine class contains static methods for performing compression/decompression operations directly
on any kind of Stream. However these methods are more difficult to use, since the caller must implement a
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_Compression_ArchiveFileStreamContext.htm">stream context</a>
that provides the file metadata which would otherwise have been provided by the filesystem. The CabInfo class
uses the CabEngine class with FileStreams to provide the more traditional file-based interface.
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="DTFAPI.chm::/html/T_Microsoft_Deployment_Compression_Cab_CabInfo.htm">CabInfo class</a></li>
<li><a href="DTFAPI.chm::/html/T_Microsoft_Deployment_Compression_Cab_CabEngine.htm">CabEngine class</a></li>
<li><a href="cabpack.htm">XPack Sample Tool</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,63 @@
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Managed Wrapper Library for Cabinet APIs</title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<link rel="stylesheet" type="text/css" href="MSDN.css">
</head>
<body id="bodyID" class="dtBODY">
<div id="nsbanner">
<div id="bannerrow1">
<table class="bannerparthead" cellspacing="0" id="Table1">
<tr id="hdr">
<td class="runninghead">Managed Libraries for Windows Installer</td>
<td class="product"></td>
</tr>
</table>
</div>
<div id="TitleRow">
<h1 class="dtH1">Managed Wrapper Library for Cabinet APIs</h1>
</div>
</div>
<div id="nstext">
<p>This is a managed library that provides the ability to
create and extract cabinet files. It uses cabinet.dll (present on all versions of Windows)
to do the actual compression/decompression. It provides access to nearly all
cabinet capabilities, including spanning of multiple cab files. It even has support for
preserving directory structures and UTF8 paths.</p>
<p>There are two ways to use the library. <a href="ms-its:MMLRef.chm::/Microsoft.Cab.CabinetInfo.html">CabinetInfo</a>
and <a href="ms-its:MMLRef.chm::/Microsoft.Cab.CabinetFileInfo.html">CabinetFileInfo</a>
(similar to DirectoryInfo and FileInfo respectively)
provide high-level object-oriented methods for doing common file-based cabinet creation and
extraction tasks. On the other hand, the <a href="ms-its:MMLRef.chm::/Microsoft.Cab.Cabinet.html">Cabinet</a>
class provides low-level access to all
functionality, and operates completely in terms of .NET Streams. The previous two classes use
the Cabinet class to do all the actual work.</p>
<p>There are also two ways to build the library.
Compiling it normally will produce the fully functional
library in the <a href="ms-its:MMLRef.chm::/Microsoft.Cab.html">Microsoft.Cab</a>
namespace, while compiling it with the <tt>/D:CABMINIMAL
/D:CABEXTRACTONLY</tt> flags will create a compact assembly with only the core extraction
functionality, in the <a href="ms-its:MMLRef.chm::/Microsoft.Cab.MiniExtract.html">Microsoft.Cab.MiniExtract</a>
namespace.</p>
<p>The cabinet library interops with native cabinet APIs which use the 'cdecl'
calling-convention. When building against .NET Framework versions before 2.0,
this library requires a special post-build step to process the UnmanagedFunctionPointerAttribute.
If you use this code in another assembly, don't forget to run <a href="augmentil.htm">AugmentIL</a>
on it to fix the delegate calling-conventions, otherwise you will encounter a
NullReferenceException when attempting to call the cabinet APIs. When building against
.NET Framework version 2.0 or later, the UnmanagedFunctionPointerAttribute.cs source file
should be omitted.</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="cabs.htm">Working with Cabinet Files</a></li>
<li><a href="ms-its:MMLRef.chm::/Microsoft.Cab.CabinetInfoMethods.html">CabinetInfo Methods</a></li>
<li><a href="ms-its:MMLRef.chm::/Microsoft.Cab.CabinetMethods.html">Cabinet Methods</a></li>
<li><a href="cabpack.htm">CabPack Sample Tool</a></li>
</ul>
<p><br/></p>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,83 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Specifying the Runtime Version</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Specifying the Runtime Version</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<a href="writingcas.htm">Writing CAs</a> &gt;
<span class="nolink">CustomAction.config</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>Every managed custom action package should contain a CustomAction.config file, even though it is not required by the toolset.
Here is a sample:</p><pre><font face="Consolas, Courier New">
&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
&lt;startup&gt;
&lt;supportedRuntime version=&quot;v2.0.50727&quot;/&gt;
&lt;/startup&gt;
&lt;/configuration&gt;</font></pre><br />
<p>The configuration file follows the standard schema for .NET Framework
configuration files <a target=_blank href="http://msdn2.microsoft.com/en-us/library/9w519wzk(VS.80).aspx">documented on MSDN</a>.</p>
<p><br/></p>
<p><b>Supported Runtime Version</b></p>
<p>In the startup section, use <a target=_blank href="http://msdn2.microsoft.com/en-us/library/w4atty68(VS.80).aspx">supportedRuntime</a>
tags to explicitly specify the version(s) of the .NET Framework that the custom action should run on.
If no versions are specified, the chosen version of the .NET Framework will be
the "best" match to what Microsoft.Deployment.WindowsInstaller.dll was built against.</p>
<p><font color="red"><b>Warning: leaving the version unspecified is dangerous</b></font>
as it introduces a risk of compatibility problems with future versions of the .NET Framework.
It is highly recommended that you specify only the version(s)
of the .NET Framework that you have tested against.</p>
<p><br/></p>
<p><b>Other Configuration</b></p>
<p>Various other kinds of configuration settings may also be added to this file, as it is a standard
<a target=_blank href="http://msdn2.microsoft.com/en-us/library/kza1yk3a(VS.80).aspx">.NET Framework application config file</a>
for the custom action.</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="buildingcas.htm">Building Managed Custom Actions</a></li>
<li><a href="caproxy.htm">Proxy for Managed Custom Actions</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,74 @@
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Proxy Class for Managed Custom Actions</title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<link rel="stylesheet" type="text/css" href="MSDN.css">
</head>
<body id="bodyID" class="dtBODY">
<div id="nsbanner">
<div id="bannerrow1">
<table class="bannerparthead" cellspacing="0" id="Table1">
<tr id="hdr">
<td class="runninghead">Managed Libraries for Windows Installer</td>
<td class="product"></td>
</tr>
</table>
</div>
<div id="TitleRow">
<h1 class="dtH1">Proxy for Managed Custom Actions</h1>
</div>
</div>
<div id="nstext">
<p>The custom action proxy allows an MSI developer to write
custom actions in managed code, while maintaing all the advantages of type 1
DLL custom actions including full access to installer state, properties,
and the session database.</p>
<p>There are generally four problems that needed to be
solved in order to create a type 1 custom action in managed code:</p>
<ol>
<li><p><strong>Exporting the CA function as a native entry point callable by
MSI:</strong> The Windows Installer engine expects to call a LoadLibrary and
GetProcAddress on the custom action DLL, so an unmanaged DLL needs to implement
the function that is initially called by MSI and ultimately returns the result.
This function acts as a proxy to relay the custom action call into the
managed custom action assembly, and relay the result back to the caller. </p>
<li><strong>Providing supporting assemblies without
requiring them to be installed as files:</strong> If a DLL custom
action runs before the product's files are installed, then it is difficult
to provide any supporting files, because of the way the CA DLL is singly
extracted and executed from a temp file. (This can be a problem for
unmanaged CAs as well.) With managed custom actions we have already hit
that problem since both the CA assembly and the MSI wrapper assembly
need to be loaded. To solve this, the proxy DLL carries an appended
cab package. When invoked, it will extract all contents of the
cab package to a temporary working directory. This way the cab package can
carry any arbitrary dependencies the custom action may require.</li>
<li><p><strong>Hosting and configuring the Common Language Runtime:</strong>
In order to invoke a method in a managed assembly from a previously
unmanaged process, the CLR needs to be "hosted". This involves choosing
the correct version of the .NET Framework to use out of the available
version(s) on the system, binding that version to the current process, and
configuring it to load assemblies from the temporary working directory.</p>
<li><p><strong>Converting the integer session handle into a
Session object:</strong> The <a href="">Session</a> class in the managed
wrapper library has a constructor which takes an integer session handle as
its parameter. So the proxy simply instantiates this object before
calling the real CA function.</p>
</ol>
<p>The unmanaged CAPack module, when used in combination with the managed proxy in
the
Microsoft.WindowsInstaller assembly, accomplishes the tasks above to enable
fully-functional managed DLL custom actions.</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="caconfig.htm">Writing the CustomAction.config file</a></li>
<li><a href="samplecas.htm">Sample C# Custom Actions</a></li>
<li><a href="buildingcas.htm">Building Managed Custom Actions</a></li>
</ul>
<p><br/></p>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,120 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Working with MSI Databases</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Working with MSI Databases</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<span class="nolink">MSI Databases</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h3>Querying a database</h3>
<pre><font face="Consolas, Courier New"> <font color=blue>using</font> (Database db = <font color=blue>new</font> Database(<font color="purple">"product.msi"</font>, DatabaseOpenMode.ReadOnly))
{
<font color=blue>string</font> value = (<font color=blue>string</font>) db.ExecuteScalar(
<font color="purple">"SELECT `Value` FROM `Property` WHERE `Property` = '{0}'"</font>, propName);
}</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Database__ctor.htm">new Database</a>
instance referring to the location of the .msi or .msm file.</p>
<p>2.&nbsp; Execute the query:</p><ul>
<li>The <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Database_ExecuteScalar.htm">ExecuteScalar</a>
method is a shortcut for opening a view, executing the view, and fetching a single value.</li>
<li>The <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Database_ExecuteQuery.htm">ExecuteQuery</a>
method is a shortcut for opening a view, executing the view, and fetching all values.</li>
<li>Or do it all manually with <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_WindowsInstaller_Database_OpenView.htm">Database.OpenView</a>,
<a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_View_Execute.htm">View.Execute</a>, and
<a href="DTFAPI.chm::/html/M_Microsoft_Deployment_WindowsInstaller_View_Fetch.htm">View.Fetch</a>.</li>
</ul>
<p><br/></p>
<h3>Updating a binary</h3>
<pre><font face="Consolas, Courier New"> Database db = <font color=blue>null</font>;
View view = <font color=blue>null</font>;
Record rec = <font color=blue>null</font>;
<font color=blue>try</font>
{
db = <font color=blue>new</font> Database(<font color="purple">"product.msi"</font>, DatabaseOpenMode.Direct);
view = db.OpenView(<font color="purple">"UPDATE `Binary` SET `Data` = ? WHERE `Name` = '{0}'"</font>, binName))
rec = <font color=blue>new</font> Record(1);
rec.SetStream(1, binFile);
view.Execute(rec);
db.Commit();
}
<font color=blue>finally</font>
{
<font color=blue>if</font> (rec != <font color=blue>null</font>) rec.Close();
<font color=blue>if</font> (view != <font color=blue>null</font>) view.Close();
<font color=blue>if</font> (db != <font color=blue>null</font>) db.Close();
}</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Database__ctor.htm">new Database</a>
instance referring to the location of the .msi or .msm file.</p>
<p>2.&nbsp; Open a view by calling one of the <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_WindowsInstaller_Database_OpenView.htm">Database.OpenView</a> overloads.</p><ul>
<li>Parameters can be substituted in the SQL string using the String.Format syntax.</li>
</ul>
<p>3.&nbsp; Create a record with one field containing the new binary value.</p>
<p>4.&nbsp; Execute the view by calling one of the <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_View_Execute.htm">View.Execute</a> overloads.</p><ul>
<li>A record can be supplied for substitution of field tokens (?) in the query.</li>
</ul>
<p>5.&nbsp; <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_WindowsInstaller_Database_Commit.htm">Commit</a> the Database.</p>
<p>6.&nbsp; <a href="DTFAPI.chm::/html/M_Microsoft_Deployment_WindowsInstaller_InstallerHandle_Close.htm">Close</a> the handles.</p>
<p><br/></p>
<h3>About handles</h3>
<p>Handle objects (Database, View, Record, SummaryInfo, Session) will remain open until
they are explicitly closed or until the objects are collected by the GC. So for the tightest
code, handle objects should be explicitly closed when they are no longer needed,
since closing them can release significant resources, and too many unnecessary
open handles can degrade performance. This is especially important within a loop
construct: for example when iterating over all the Records in a table, it is much cleaner
and faster to close each Record after it is used.</p>
<p>The handle classes in the managed library all extend the
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_InstallerHandle.htm">InstallerHandle</a>
class, which implements the IDisposable interface. This makes them easily managed with C#'s
using statement. Alternatively, they can be closed in a finally block.</p>
<p>As a general rule, <i>methods</i> in the library return new handle objects that should be managed
and closed by the calling code, while <i>properties</i> only return a reference to a prexisting handle
object.</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="powerdiff.htm">MSI Diff Sample Tool</a></li>
<li><a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_Database.htm">Database Class</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,66 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Debugging Managed Custom Actions</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Debugging Managed Custom Actions</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<span class="nolink">Debugging</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>There are two ways to attach a debugger to a managed custom action.</p>
<p><b>Attach to message-box:</b> Add some temporary code to your custom action to display a
message box. Then when the message box pops up at install time, you can attch your
debugger to that process (usually identifiable by the title of the message box).
Once attached, you can ensure that symbols are loaded if necessary (they will be automatically
loaded if PDB files were embedded in the CA assembly at build time), then set breakpoints
anywhere in the custom action code.</p>
<p><b>MMsiBreak environment variable:</b> When debugging <i>managed</i> custom actions,
you should use the MMsiBreak environment variable instead of MsiBreak. Set the MMsiBreak
variable to the custom action entrypoint name. (Remember this might be different from
the method name if it was overridden by the CustomActionAttribute.) When the CA proxy
finds a matching name, the CLR JIT-debugging dialog
will appear with text similar to "An exception 'Launch for user' has occurred
in <i>YourCustomActionName</i>." The debug break occurs after the custom
action assembly has been loaded, but just before custom action method is invoked.
Once attached, you can ensure that symbols are loaded if necessary,
then set breakpoints anywhere in the custom action code. Note: the MMsiBreak
environment variable can also accept a comma-separated list of action names, any of
which will cause a break when hit.</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,88 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Dependencies</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Dependencies</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="about.htm">Overview</a> &gt;
<span class="nolink">Dependencies</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>This page lists all the components that the DTF project depends on, at build time and at run-time.</p>
<h3>Build-time Dependencies</h3>
<ul>
<li><p><b>Visual Studio / .NET Framework</b> - Most of DTF can be built with Visual Studio 2005 &
.NET Framework 2.0. However, the LINQ project requires VS 2008 & .NET Framework 3.5.</p></li>
<li><p><b>Sandcastle</b> - .NET documentation build engine from Microsoft, used to process all the XML doc-comments
in DTF libraries into DTFAPI.chm.
<a href="http://www.codeplex.com/Sandcastle/" target="_blank">(official site)</a></p></li>
<li><p><b>Sandcastle Builder</b> - Sandcastle by itself is complex and difficult to use; this free tool
from Codeplex provides an easy-to-use project system around it to automate the documentation build process.
<a href="http://www.codeplex.com/SHFB/" target="_blank">(project link)</a></p></li>
<li><p><b>HTML Help Workshop</b> - Tools for building HTML Help 1.x (CHM files). Used to build DTF.chm.
<a href="http://msdn2.microsoft.com/en-us/library/ms669985.aspx" target="_blank">(download link)</a></p></li>
</ul>
<h3>Run-time Dependencies</h3>
<ul>
<li><p><b>.NET Framework</b> - Most of DTF requires .NET Framework 2.0. (.NET 1.1 is no longer supported.)
The only exception is the LINQ assembly which requires .NET Framework 3.5.</p></li>
<li><p><b>Windows Installer</b> - Windows Installer introduced new APIs and capabilities with each successive
version. Obviously, the corresponding functionality in the managed APIs is only available when the required
version of the Windows Instaler (msi.dll) is installed on the system. Use the Installer.Version property
to easily check the currently installed MSI version. Attempting to use an API not supported by the current
version will result in an EntryPointNotFoundException. To check what version is required for a particular API,
see the documentation link to the corresponding unmanaged API in MSI.chm.</p>
<p>In some instances when a newer version of MSI provides an "Ex" alternative to a function, only the "Ex"
function is used by the managed library. This may hide some functionality that would have otherwise been
available on a system with an older version of MSI.</p></li>
<li><p><b>cabinet.dll</b> - The DTF cabinet compression library uses cabinet.dll to implement the
low-level cabinet compression and decompression. This DLL is part of all versions of Windows,
located in the system directory.</p></li>
<li><p><b>System.IO.Compression.DeflateStream</b> - The DTF zip compression library uses this class
to implement the low-level zip compression and decompression. This class is part of .NET Framework
2.0 and later.</p></li>
</ul>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,34 @@
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Managed Wrapper for Binary File Patch APIs</title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<link rel="stylesheet" type="text/css" href="MSDN.css">
</head>
<body id="bodyID" class="dtBODY">
<div id="nsbanner">
<div id="bannerrow1">
<table class="bannerparthead" cellspacing="0" id="Table1">
<tr id="hdr">
<td class="runninghead">Managed Libraries for Windows Installer</td>
<td class="product"></td>
</tr>
</table>
</div>
<div id="TitleRow">
<h1 class="dtH1">Managed Wrapper for Binary File Patch APIs</h1>
</div>
</div>
<div id="nstext">
<p>The binary file patch creation and application APIs (supplied by MsPatchC.dll and
MsPatchA.dll) are wrapped in the Microsoft.WindowsInstaller.FilePatch.dll assembly.</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.FilePatch.html">FilePatch Class</a></li>
</ul>
<p><br/></p>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,437 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Change History</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Change History</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="about.htm">Overview</a> &gt;
<span class="nolink">Change History</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h3><b>2007-07-03</b></h3>
<i>See <a href="whatsnew.htm">What's New?</a></i><br />&nbsp;<br />&nbsp;<br />
<hr size="2"/>
<h3><b>2005-03-30</b></h3>
<ul>
<li>New custom action proxy<ul>
<li><b>Managed custom actions use an XML config file to specify the CLR version.</b></li>
<li>New CAPack module is an unmanaged self-extracting CA DLL that can wrap both
managed and unmanaged custom actions. (The old managed CAProxy module is obsolete.)</li>
<li>Custom action build process is different but still complicated --
see documentation for details.</li>
<li>CustomActionAttribute no longer accepts the optional NativeDependencies
parameter since it does not apply to the new proxy (all packaged files
are always extracted and available when the CA executes). </li>
</ul></li>
<li>64bit support<ul>
<li>Various code fixes to pointer/handle types and structure alignments.</li>
<li>Cabinet and MSI libraries tested on AMD64 CLR.</li>
<li>Unmanaged and managed parts of custom action proxy tested on AMD64.</li>
</ul></li>
<li>MSI 3.1 APIs added:<ul>
<li>Installer.SetExternalUI(ExternalUIRecordHandler)</li>
<li>Installer.NotifySidChange</li>
</ul></li>
<li>Code builds easier with .NET Famework 2.0<ul>
<li>AugmentIL post-build step is no longer necessary when compiling the cabinet code
against .NET Framework 2.0, which has builtin support for cdecl delegates.</li>
<li>All C# code compiles against .NET Framework 2.0 without obsolete warnings,
when setting the NETFX2 preprocessor define.</li>
<li>Same code is still compatible with .NET Framework 1.0 + AugmentIL.</li>
</ul></li>
<li>Miscellaneous bugfixes/changes:<ul>
<li>InstallPackage.ExtractFiles could fail in some cominations of
compressed/uncompressed files - fixed.</li>
<li>Installer.DeterminePatchSequence was broken due to an incorrect interop struct - fixed.</li>
<li>CabinetInfo and CabinetFileInfo classes made serializable.</li>
<li>Added Session.FormatString method to simplify formatting a string with
property substitutions.</li>
</ul></li>
<li>Documentation updates:<ul>
<li>Updated all documentation for new CA proxy.</li>
<li>Added new topic discussing InstallUtil.</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2004-04-13</b></h3>
<ul>
<li>Documentation<ul>
<li>Consolidated all documentation into a single CHM file.</li>
<li>Added new topics about working with MSI databases & cabinet files,
to help new users get oriented more easily.</li>
</ul></li>
<li>WindowsInstaller<ul>
<li>Removed [Beta] tags from MSI 3.0 APIs, but otherwise there
have been no changes since 3.0 Beta 1.<ul>
<li>Be warned these are still the least-tested parts of
the library, so early users may encounter bugs.</li>
</ul></li>
</ul></li>
<li>InstallPackage<ul>
<li>Fixed InstallPackage.ExtractFiles() bug when directory doesn't exist.</li>
<li>Added ability to handle uncompressed files in a package marked as compressed.</li>
</ul></li>
<li>Cabinet<ul>
<li>Fixed improper handling of file attributes.<ul>
<li>This bug caused some packages to not be extractable by other tools.</li>
</ul></li>
<li>Added support for UTF filenames.<ul>
<li>Non-ASCII filenames will automatically be stored as UTF-8.
(But note most other tools don't know how to extract them.)</li>
</ul></li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-10-13</b></h3>
<ul>
<li>Cab<ul>
<li>Fixed a bug introduced in v2.4.0 that caused files to be left in the %TEMP%
directory after creating a cab.</li>
<li>Unsealed the CabinetInfo, CabinetFileInfo, CabinetStatus classes and made a few methods
protected and virtual.</li>
</ul></li>
<li>AugmentIL<ul>
<li>Fixed a bug that sometimes caused a crash when specifying a relative output path
on the command-line.</li>
<li>Fixed a bug that sometimes caused the Win32 version to be missing from the output file.</li>
</ul></li>
<li>Samples\Diff: added new sample tool<ul>
<li>Recursively diffs directories, MSIs, MSPs, CABs, other files.</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-09-23</b></h3>
<ul>
<li>Cab<ul>
<li>Fixed a bug that caused compressing very large files/file sets to use way too
much memory. Performance on large inputs is now within a few % of native cab tools
(sometimes even a little faster!) for the same compression level.</li>
</ul></li>
<li>WindowsInstaller<ul>
<li>All the new MSI 3.0 beta APIs are wrapped, resulting in the following additions:<ul>
<li>New classes - Product, Patch (for accessing sourcelist and other config)</li>
<li>New methods on Install class - GetProducts, GetPatches, RemovePatches,
ApplyMultiplePatches, DetermineApplicablePatches, ExtractPatchXmlData</li>
<li>New enumerations - InstallContext, PatchStates, SourceType</li>
<li>Additional InstallProperty values</li>
</ul></li>
<li>Note, MSI 3.0 support should be considered preliminary for now,
as APIs (both native and managed) are subject to change.</li>
<li>For MSI 2.0 compatibility, developers should not use any classes or
methods that are marked as [MSI 3.0 beta] in the documentation.</li>
<li>And unrelated to 3.0, a few additional enums have been added:
DialogAttributes, ControlAttributes, CustomActionTypes,
IniFileAction, RegistryRoot, RemoveFileInstallMode,
ServiceControlEvents, ServiceInstallFlags, TextStyles,
UpgradeAttributes, LocatorType</li>
<li>Also made a few minor non-breaking changes to keep the library FxCop-clean.</li>
</ul></li>
<li>AugmentIL<ul>
<li>Added support for strongname signing and delay-signing. AugmentIL tries to
locate the keyfile using the AssemblyKeyFileAttribute, or you may specify the
path with the new /key option.</li>
<li>All &quot;released&quot; assemblies will now be strongname-signed
(with an unofficial key).</li>
</ul></li>
<li>CAProxy<ul>
<li>Added support for NativeDependencies property on CustomActionAttribute. This enables
custom actions to P/Invoke into native DLLs that are carried with them.</li>
</ul></li>
<li>Samples\SampleCAs<ul>
<li>In SampleCA2, changed MessageBox.Show(&quot;&quot;) to session.Message(User,&quot;&quot;),
because generally it is a bad practice for CAs to show independent UI.</li>
<li>Added test of CustomActionAttribute.NativeDependencies functionality.</li>
</ul></li>
<li>Samples\CabPack: added new sample<ul>
<li>Demonstrates &amp; tests the cab library by creating self-extracting packages</li>
</ul></li>
<li>Samples\Inventory: added new sample<ul>
<li>Shows a hierarchical, relational, searchable view of all of the product,
feature, component, file, and patch data managed by MSI, for all products
installed on the system.</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-09-12</b></h3>
<ul>
<li>Cab:<ul>
<li>Added CabinetInfo.CompressDirectory method, capable of compressing an
entire directory tree structure.</li>
<li>Updated documentation of various methods concerning support of directory
structure inside cabs.</li>
<li>CabinetInfo case-sensitivity was inconsistent -
now it is case-insensitive by default, though case is still preserved</li>
<li>Separated assembly attributes into assembly.cs</li>
</ul></li>
<li>Msi:<ul>
<li>InstallerException and subclasses automatically get extended error data
from MSI's last-error-record when available. The data is stored
in the exception and made available through the GetErrorRecord()
method, and the exception's Message includes the formatted error
message and data. This makes most exceptions extremely informative!</li>
<li>Added View.GetValidationErrors() method, and supporting ValidationErrorInfo
struct and ValidationError enum. This wrapper for the MsiViewGetError
API had been accidentally left out.</li>
<li>Session.Message() now supports message-box flags to specify buttons &amp; icon</li>
<li>Added doc remarks to various methods about closing handles.</li>
<li>Separated assembly attributes into assembly.cs</li>
</ul></li>
<li>AugmentIL:<ul>
<li>Recent builds of ildasm v2.0.* have a slightly different output format,
which could break AugmentIL in some cases - fixed</li>
</ul></li>
<li>SampleCAs:<ul>
<li>Removed 'using' clause from SampleCA1 -- there's no need to close the session's active database handle</li>
</ul></li>
<li>Documentation:<ul>
<li>Added note to ReadMe about compiling the cab source into another assembly</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-08-07</b></h3>
<ul>
<li>Cab:<ul>
<li>CabinetInfo.IsValid() usually returned false even for valid cabs - fixed</li>
<li>Extracting cab files with null timestamps generated exception - fixed</li>
</ul></li>
<li>Msi:<ul>
<li>Added InstallCanceledException, subclass of InstallerException;
Methods which may be canceled by the user can throw this exception</li>
<li>Added MessageResult enumeration;
Used by Session.Message() and ExternalUIHandler delegate</li>
<li>Installer.EnableLog() now supports extended attributes correctly:
Append mode and flush-every-line</li>
<li>Added Session.DoActionSequence() -
This wrapper for the MsiSequence API had been accidentally left out</li>
</ul></li>
<li>CAProxy:<ul>
<li>Catches InstallCanceledException, returns ERROR_INSTALL_USEREXIT
so CA developer doesn't necessarily have to handle the exception</li>
</ul></li>
<li>Msi\Package:<ul>
<li>Added TransformInfo class: metadata about an individual patch transform</li>
<li>Added PatchPackage.GetTransform*() methods which return TransformInfo</li>
</ul></li>
<li>Documentation:<ul>
<li>Added section to ReadMe.htm about building managed custom actions</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-06-02</b></h3>
<ul>
<li>Msi:<ul>
<li>Validation didn't work on merge modules - fixed</li>
</ul></li>
<li>CAProxy:<ul>
<li>Was broken in 2.1 - fixed</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-05-14</b></h3>
<ul>
<li>Msi:<ul>
<li>External UI handler didn't survive a garbage collection - fixed</li>
<li>Validation engine was completely broken - now it should work
at least for MSIs which are already mostly valid</li>
<li>Added DynamicLoad property to CustomActionAttribute<br />
Usage: set DynamicLoad=false when using XmlSerialization; default is true</li>
</ul></li>
<li>Msi\Package:<ul>
<li>File extraction and update methods didn't work on merge modules - fixed</li>
<li>Made file update code slightly more robust</li>
<li>Removed hard-reference to the FilePatch assembly - now it is only
loaded if working with binary file patches</li>
</ul></li>
<li>AugmentIL:<ul>
<li>AugmentIL would crash if some input files had read-only attr - fixed</li>
<li>Made /verbose switch slightly more verbose</li>
</ul></li>
<li>CAProxy:<ul>
<li>Added support for the DynamicLoad property of CustomActionAttribute</li>
<li>Added MMsiBreak debugging functionality - see doc</li>
</ul></li>
<li>Samples\WiFile:<ul>
<li>Added /l (list files) switch</li>
</ul></li>
<li>Samples\SampleCAs:<ul>
<li>In the makefile the comments about debug builds had an error;
Now the sample builds debug packages (correctly) by default.</li>
</ul></li>
<li>Documentation:<ul>
<li>Wrote AugmentIL.htm describing the AugmentIL tool and its options.</li>
<li>Wrote WiFile.htm describing the WiFile sample tool.</li>
<li>Added section to ReadMe.htm about debugging managed custom actions.</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-03-31</b></h3>
<ul>
<li>Msi: Implemented the remaining APIs, also minor improvements and bugfixes<ul>
<li>All published APIs are wrapped, with the exception of four:
MsiGetFileSignatureInformation (because I don't know of a .NET analog
for the returned certificate structure), and 3 APIs for previewing UI</li>
<li>Database.OpenView and Database.Execute* now take String.Format style params</li>
<li>Database.ApplyTransform can optionally use the error-suppression flags
stored in the transform summary info</li>
<li>Added a few supporting enumerations and structures for the remaining APIs</li>
<li>InstallerException gets a descriptive message for any MSI or system error</li>
<li>Fixed a bug in InstallerException which would usually report &quot;error 0&quot;</li>
<li>Added optimization for setting a Record field to a MemoryStream</li>
<li>Record.GetStream is capable of extracting substorages</li>
<li>Moved InstallPath class to Microsoft.WindowsInstaller.Package assembly</li>
</ul></li>
<li>Msi\FilePatch: added new project<ul>
<li>Binary file patch API wrapper</li>
</ul></li>
<li>Msi\Package: added new project<ul>
<li>Helper classes for working with MSI and MSP packages</li>
</ul></li>
<li>Cab: some minor bugfixes<ul>
<li>Cabinet.Extract(stream, name) threw a NullReferenceException if the file
didn't exist in the cab -- now it returns null</li>
<li>CabinetInfo.CompressFileSet() was broken -- fixed</li>
<li>If a Cabinet callback throws an exception, it is propogated as the
inner-exception of the CabinetException</li>
</ul></li>
<li>Samples\WiFile: added new sample<ul>
<li>Demonstrates some features of InstallPackage class in Msi\Package project</li>
</ul></li>
</ul>
<hr size="2"/>
<h3><b>2003-03-20</b></h3>
Documentation!<ul>
<li>Msi and Cab sources include complete C# XML documentation.</li>
<li>Msi and Cab makefiles generate XML documentation files.</li>
<li>Reference CHM compiled from XML documentation with NDoc.</li>
</ul>
<p>I am aware that exceptions are still not documented in most areas.
Other than that, feel free to send me a note if it's still not clear
how to use parts of the API after reading the documentation.</p>
<p>Version is still 1.1 because there are no code changes in this release.</p>
<hr size="2"/>
<h3><b>2003-03-13</b></h3>
<ul>
<li>Msi: lots of small improvements for usability and consistency<ul>
<li>Reworked ExternalUIHandler support</li>
<li>Added Installer properties/methods:<ul>
<li>Components</li>
<li>ComponentClients()</li>
<li>ComponentState()</li>
<li>ComponentPath()</li>
<li>EnableLog()</li>
</ul></li>
<li>Added Session.EvaluateCondition() method</li>
<li>Improved exception-handling in many methods in Installer, Database,
&amp; Session classes</li>
<li>Added extensive XML doc-comments to Installer, Database, View,
&amp; Session classes</li>
<li>A few breaking changes:<ul>
<li>View.ModifyMode enumeration moved outside View and
renamed ViewModifyMode</li>
<li>InstallLogMode enumeration renamed to InstallLogModes
(naming convention for bitfields)</li>
<li>Record constructor takes arbitrary number of parameters</li>
</ul></li>
</ul></li>
<li>AugmentIL: almost completely rewritten<ul>
<li>Ildasm/ilasm steps are built-in<ul>
<li>The round-trip can be done in one step</li>
<li>IL source input/output is still supported</li>
</ul></li>
<li>Never throws an unhandled exception</li>
<li>Organized command-line options, consistent with other .NET tools</li>
<li>Uses a plugin architecture to allow additional augmentations</li>
</ul></li>
<li>CAProxy: Added AIL_CAProxy.cs - AugmentIL plugin generates CA proxy methods</li>
<li>SampleCAs: Updated makefile for new AugmentIL usage</li>
</ul>
<hr size="2"/>
<h3><b>2003-01-16</b></h3>
<ul>
<li>ReadMe.htm: Added section on writing managed CAs</li>
<li>SampleCAs: Added missing reference to System.Windows.Forms.dll to the makefile</li>
<li>AugmentIL: Added specific warning messages for when CA method has wrong signature</li>
<li>Put sources in Toolbox-hosted Source Depot.</li>
</ul>
<hr size="2"/>
<h3><b>2003-01-14</b></h3>
Initial posting to http://toolbox
<p>&nbsp;</p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,94 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>About InstallUtil</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">About InstallUtil</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<span class="nolink">InstallUtil</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>
InstallUtil is often considered as another option for executing MSI custom actions
written in managed code. But in most cases it is not the best solution, for a number
of reasons.</p>
<p>
InstallUtil (in either InstallUtil.exe or InstallUtilLib.dll form) is a .NET Framework
tool for executing the System.Configuration.Installer classes that are implemented
in an assembly. That way the assembly can contain any special code required to install
itself and uninstall itself. Essentially it is the .NET replacement for COM self-registration
aka DllRegisterServer.</p>
<p>
Self-reg or System.Configuration.Installer is convenient for development use in
order to test code without creating an actual setup package, or for an IDE which
wants to generate self-installing code. But experienced setup developers and the
<a href="MSI.chm::/setup/selfreg_table.htm">Windows Installer documentation</a>
all agree that self-reg is a bad practice for a
production-quality setup. The current theory of state-of-the-art setup is that it
should be as data-driven as possible. That is, the setup package describes as fully
as possible the desired state of the system, and then the installer engine calculates
the necessary actions to install, uninstall, patch, etc.</p>
<p>
S.C.I encourages developers to write code for things such as registering services
or registering COM classes or other things which are more appropriately done using
built-in MSI functionality (the ServiceInstall and Registry tables). The Visual
Studio .NET wizards also tend to generate this kind of install code. Again, that
is nice for development but not good for real installations. You end up with similar
but slightly different code in many places for doing the same thing. And that code
is a black-box to the installer engine.</p>
<p>
An ideal MSI custom action is a logical extension of the setup engine, meaning it
is data-driven and written in a very generic way to read from existing or custom
tables in the MSI database, following a very similar pattern to the built-in actions.
This makes the CA re-usable, and makes the installation more transparent. S.C.I
custom actions invoked by InstallUtil cannot be data-driven because they don't have
full access to the install session or database. They also cannot write to the install
session's regular MSI log, but instead use a separate log which is bad for supportability.</p>
<p>
InstallUtil also requires that the assembly be installed before the CA is able to
execute. This is a problem for CAs that need to execute during the UI phase, or
gather information before installation. For that purpose MSI allows custom action
binaries to be embedded as non-installed files, but InstallUtil cannot make use
of those.</p>
<p>
Custom actions developed with DTF have none of the limitations of InstallUtil,
giving a setup developer full capabilities to write well-designed custom actions,
only now in managed code.
</p>
<p>&nbsp;</p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,78 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Windows Installer System Inventory Viewer</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Windows Installer System Inventory Viewer</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="samples.htm">Samples</a> &gt;
<span class="nolink">Inventory</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>This application shows a hierarchical, relational, searchable
view of all of the product, feature, component, file, and patch
data managed by MSI, for all products installed on the system.</p>
<p><br/></p>
<h4>Navigation</h4>
<ol>
<li><p>The tree on the left is self-explanatory.</p></li>
<li><p>Click on a row-header (grey box on the left side of the
grid) to jump to a table with more details about the item referred
to by that row. For example, clicking on a row-header of a
table that lists components will take you to a table that lists
the files in that component. Not every table has this ability,
but the cursor will turn to a hand shape to indicate when this is
possible.</p></li>
<li><p>Also you can navigate back and forward through your history
using the buttons in the application or mouse buttons 4 and 5.</p></li>
</ol>
<p><br/></p>
<h4>Searching</h4>
<p>The search feature is not hard to find. By default, searches
are limited to the current table. However, if you choose to find
&quot;In Subtree&quot; by checking the box, the search will include
the current table as well as all tables under the current location in
the tree. While this can take a long time if there is a lot of
data under the current node, you can stop the search at any time with
the stop button. The search pauses when a match is found, but
clicking &quot;Find&quot; again will continue the same search from that
point (unless you uncheck the &quot;Continue&quot; checkbox or change
the search string).</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,53 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Managed Custom Actions</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Managed Custom Actions</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<span class="nolink">Managed CAs</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<ul>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="caconfig.htm">Specifying the Runtime Version</a></li>
<li><a href="buildingcas.htm">Building Managed Custom Actions</a></li>
<li><a href="debuggingcas.htm">Debugging Managed Custom Actions</a></li>
<li><a href="installutil.htm">About InstallUtil</a></li>
</ul>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,59 @@
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Included Components</title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<link rel="stylesheet" type="text/css" href="MSDN.css">
</head>
<body id="bodyID" class="dtBODY">
<div id="nsbanner">
<div id="bannerrow1">
<table class="bannerparthead" cellspacing="0" id="Table1">
<tr id="hdr">
<td class="runninghead">Managed Libraries for Windows Installer</td>
<td class="product"></td>
</tr>
</table>
</div>
<div id="TitleRow">
<h1 class="dtH1">Helper Classes for Windows Installer Packages</h1>
</div>
</div>
<div id="nstext">
<p>Included are some useful helper classes for working with
MSI and MSP packages:</p>
<ul>
<li><p><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.InstallPackage.html"
><strong>InstallPackage</strong></a> - extends the Database class to provide powerful
package-based operations such as:</p>
<ul>
<li>direct extraction of files to uncompressed source
path
<li>updating files from uncompressed source path back
into the compressed source for the package (including updating file
metadata)
<li>applying a patch directly to the package
<li>consolidating a package with uncompressed source files or multiple msm-cabs
into a package with a single compressed cabinet</li>
</ul>
<P></P>
<li><p><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.InstallPathMap.html"
><strong>InstallPathMap</strong>, <a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.InstallPath.html"
><strong>InstallPath</strong></a> - represent the directory structure
of an installation package, including file, component, and directory source and target
install paths. Accessible by file, component, or directory keys; searchable by
filename.</p>
<li><p><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.PatchPackage.html"
><strong>PatchPackage</strong></a> - allows convenient access to patch properties,
and analysis and extraction of transforms</p></li>
</ul>
<p><br/></p>
<p>These classes are in the Microsoft.WindowsInstaller.Package.dll assembly.</p>
<p><br/></p>
<p><b>See also:</b></p>
<p>The <a href="wifile.htm">WiFile</a> sample tool demonstrates some usage of the
InstallPackage class.</p>
<p><br/></p>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,80 @@
<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>Included Components</title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<link rel="stylesheet" type="text/css" href="MSDN.css">
</head>
<body id="bodyID" class="dtBODY">
<div id="nsbanner">
<div id="bannerrow1">
<table class="bannerparthead" cellspacing="0" id="Table1">
<tr id="hdr">
<td class="runninghead">Managed Libraries for Windows Installer</td>
<td class="product"></td>
</tr>
</table>
</div>
<div id="TitleRow">
<h1 class="dtH1">Managed wrapper library for Windows Installer APIs</h1>
</div>
</div>
<div id="nstext">
<p>Microsoft.WindowsInstaller.dll is a complete .NET wrapper for the
Windows Installer APIs. It provides a convenient object model that is
comfortable to .NET developers and still familiar to anyone who has used
the MSI scripting object model.</p>
<h3>Notes</h3>
<ul>
<li><p>All published MSI APIs are wrapped, with the exception of four:
MsiGetFileSignatureInformation (because I don't know of a .NET analog for the
returned certificate structure), and three APIs for previewing UI dialogs.
Other than that, you should be able to do everything that you can
do via the C APIs or the COM automation interface.</p>
<li><p>Some parts of this code have never had a formal test
pass, so use at your own risk. But much of the code is exercised daily, used
by the Developer Division Sustaining Engineering team's BRIQS system to build
and test patches. And it has been in use by many other teams for over two
years now with only a few minor fixes, so it can be considered very stable.</p>
<li><p>Despite its official-sounding namespace, this assembly is not officially
sanctioned by the Windows Installer team. But currently there are not any
plans for an official set of managed even in Longhorn, so I don't see a
conflict for now.</p></li>
</ul>
<h3>Why rewrite it?</h3>
<p>It is possible to access MSI's COM Automation interfaces via C# and VB.NET.
So why create yet another wrapper? Here are some of my reasons:</p>
<ul>
<li><p>One of the primary things I wanted to be able to do
was write custom actions in C#. The automation interface was not usable in
that case, because there is no way to convert the integer session handle
(received as a parameter to the type 1 custom action function) into a Session
automation object.</p>
<li><p>The automation interface does not provide a way to
specify an external UI handler. Besides external UI, this is also needed
to do validation.</p>
<li><p>The automation interface does not provide a way to
explicitly close handles (other than Views). I ran into this problem when I
wanted to programmatically delete a database that I'd just finished using, but
couldn't because it was still open!</p>
<li><p>Finally, COM Automation is somewhat slower than invoking
the APIs directly.</p></li>
</ul>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.html">Microsoft.WindowsInstaller Namespace</a></li>
<ul>
<li><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.Installer.html">Installer Class</a></li>
<li><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.Database.html">Database Class</a></li>
<li><a href="ms-its:MMLRef.chm::/Microsoft.WindowsInstaller.Session.html">Session Class</a></li>
</ul>
<li><a href="msihelper.htm">Helper Classes for Windows Installer Packages</a></li>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="databases.htm">Working with MSI Databases</a></li>
</ul>
<p><br/></p>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,86 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Working with Install Packages</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Working with Install Packages</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<span class="nolink">Install Packages</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h3>Updating files in a product layout</h3>
<p>The InstallPackage class makes it easy to work with files and cabinets
in the context of a compressed or uncompressed product layout.</p>
<p>This hypothetical example takes an IDictionary 'files' which maps file keys to file paths. Each
file is to be updated in the package layout; cabinets are even recompressed if necessary to include the new files.</p>
<pre><font face="Consolas, Courier New"> <font color=blue>using</font> (InstallPackage pkg = <font color=blue>new</font> InstallPackage(<font color=purple>"d:\builds\product.msi"</font>,
DatabaseOpenMode.Transact))
{
pkg.WorkingDirectory = Path.Combine(Path.GetTempFolder(), <font color=purple>"pkgtmp"</font>);
<font color=blue>foreach</font> (string fileKey in files.Keys)
{
<font color=blue>string</font> sourceFilePath = files[fileKey];
<font color=blue>string</font> destFilePath = pkg.Files[fileKey].SourcePath;
destFilePath = Path.Combine(pkg.WorkingDirectory, destFilePath);
File.Copy(sourceFilePath, destFilePath, <font color=blue>true</font>);
}
pkg.UpdateFiles(<font color=blue>new</font> ArrayList(files.Keys));
pkg.Commit();
Directory.Delete(pkg.WorkingDirectory, <font color=blue>true</font>);
}</font></pre><br />
<p>1.&nbsp; Create a <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Package_InstallPackage__ctor.htm">new InstallPackage</a>
instance referring to the location of the .msi. This is actually just a specialized subclass of a Database.</p>
<p>2.&nbsp; Set the <a href="DTFAPI.chm::/html/P_Microsoft_Deployment_WindowsInstaller_Package_InstallPackage_WorkingDirectory.htm">WorkingDirectory</a>.
This is the root directory where the package expects to find the new source files.</p>
<p>3.&nbsp; Copy each file to its proper location in the working directory. The
<a href="DTFAPI.chm::/html/P_Microsoft_Deployment_WindowsInstaller_Package_InstallPackage_Files.htm">InstallPackage.Files</a>
property is used to look up the relative source path of each file.</p>
<p>4.&nbsp; Call <a href="DTFAPI.chm::/html/Overload_Microsoft_Deployment_WindowsInstaller_Package_InstallPackage_UpdateFiles.htm">InstallPackage.UpdateFiles</a>
with the list of file keys. This will re-compress and package the files if necessary, and also update the
following data: File.FileSize, File.Version, File.Language, MsiFileHash.HashPart*.</p>
<p>5.&nbsp; Commit the database changes and cleanup the working directory.</p>
</ul>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="wifile.htm">WiFile Sample Tool</a> - a more complete tool that expands on the above example.</li>
<li><a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_Package_InstallPackage.htm">InstallPackage Class</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,71 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>MSI, MSP, CAB Diff Tool</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">MSI, MSP, CAB Diff Tool</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="samples.htm">Samples</a> &gt;
<span class="nolink">DDiff</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h2>MSI, MSP, CAB Diff Tool</h2>
<p><pre><font face="Consolas, Courier New">Usage: DDiff target1 target2 [options]
Example: DDiff d:\dir1 d:\dir2
Example: DDiff setup1.msi setup2.msi
Example: DDiff patch1.msp patch2.msp -patchtarget target.msi
Example: DDiff package1.cab package2.cab
Options:
/o [filename] Output results to text file (UTF8)
/p [package.msi] Diff patches relative to target MSI</font></pre>
</p>
<p><br/></p>
<p>The following types of inputs can be diffed:
<ul>
<li><b>Directories</b>: files and subdirectories are compared.</li>
<li><b>Cab files</b>: internal file list and files are compared.</li>
<li><b>MSI/MSM database files</b>: summary info, tables, and embedded binary and cab streams are compared.</li>
<li><b>MSP files</b>: summary info and embedded file cab are compared. When a patch target MSI is provided, the MSP's tables are also compared.</li>
<li><b>Versioned files</b>: Win32 file version is compared.</li>
<li><b>Text files</b>: if diff.exe is in the path, it is used to get a line-by-line diff.</li>
<li><b>Other files</b>: file size and bytes are compared.</li>
</ul>
All processing is done recursively. So a versioned file within a cab within an MSI within a directory will have meaningful diff results.</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,84 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Sample C# Custom Action</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Sample C# Custom Action</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<a href="writingcas.htm">Writing CAs</a> &gt;
<span class="nolink">C# Sample</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>MSI custom actions are MUCH easier to write in C# than
in C++!</p><pre><font face="Consolas, Courier New"> [CustomAction]
<font color=blue>public</font> <font color=blue>static</font> ActionResult SampleCustomAction1(Session session)
{
session.Log(<font color="purple">"Hello from SampleCA1"</font>);
<font color=blue>string</font> testProp = session[<font color="purple">"SampleCATest"</font>];
<font color=blue>string</font> testProp2;
testProp2 = (<font color="blue">string</font>) session.Database.ExecuteScalar(
<font color="purple">"SELECT `Value` FROM `Property` WHERE `Property` = 'SampleCATest'"</font>);
<font color=blue>if</font>(testProp == testProp2)
{
session.Log(<font color="purple">"Simple property test passed."</font>);
<font color=blue>return</font> ActionResult.Success;
}
<font color=blue>else</font>
<font color=blue>return</font> ActionResult.Failure;
}
</font></pre>
<p>A sample CA project with two CAs is included in the
Samples\ManagedCA directory.&nbsp; Running the CustomActionTest project will package the CA and insert
it into a test MSI. The MSI will invoke the custom actions, but it will not install anything
since the second sample CA returns ActionResult.UserExit.
</p>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="writingcas.htm">Writing Managed Custom Actions</a></li>
<li><a href="caconfig.htm">Specifying the Runtime Version</a></li>
<li><a href="databases.htm">Working with MSI Databases</a></li>
<li><a href="buildingcas.htm">Building Managed Custom Actions</a></li>
<li><a href="debuggingcas.htm">Debugging Managed Custom Actions</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,59 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Sample Applications</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Sample Applications</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<span class="nolink">Samples</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>Besides the simple managed custom action sample, there are three functional
and useful sample tools included in this distribution:</p>
<p><a href="Inventory.htm"><b>MSI Inventory</b></a><br/>
Shows a hierarchical, relational, searchable view of all of the product,
feature, component, file, and patch data managed by MSI, for all products
installed on the system.</p>
<p><a href="WiFile.htm"><b>WiFile</b></a><br/>
Extracts and updates cabbed files in an MSI setup.</p>
<p><a href="CabPack.htm"><b>CabPack</b></a><br/>
Creates simple self-extracting cab packages. OK, so this one isn't
especially useful as a tool, but the code should be helpful.</p>
<p><a href="PowerDiff.htm"><b>DDiff</b></a><br/>
Recursively diffs MSI, MSP, CAB, and other files and directories.
Much more thorough than widiffdb.vbs.</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,52 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Support/Bugs</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Support/Bugs</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="about.htm">Overview</a> &gt;
<span class="nolink">Support/Bugs</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p>Please send general support questions or comments to the
<a href="mailto:wix-users@sourceforge.net">wix-users</a> discussion list.</p>
<p>Bugs, suggestions, or feature requests can be submitted at the
<a href="http://wix.sourceforge.net/">WiX project</a>
on Sourceforge.net.</p>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,50 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Deployment Tools Foundation Development Guide</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Deployment Tools Foundation Development Guide</span><br />
<div id="toolbar">
<span id="chickenFeet">
<span class="nolink">Development Guide</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<ul>
<li><a href="managedcas.htm">Managed Custom Actions</a></li>
<li><a href="databases.htm">Working with MSI Databases</a></li>
<li><a href="cabs.htm">Working with Cabinet Files</a></li>
<li><a href="packages.htm">Working with Install Packages</a></li>
<li><a href="samples.htm">Sample Applications</a></li>
</ul>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,257 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>What's New?</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">What's New?</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="about.htm">Overview</a> &gt;
<span class="nolink">What's New?</span>
</span>
<span id="languageFilter">2007-07-03</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<h3>Highlights</h3>
<ul>
<li><p>New project name name "Deployment Tools Foundation", and
new namespaces <font face="Consolas, Courier New">Microsoft.Deployment.*</font></p></li>
<li><p>Added ZIP compression library</p></li>
<li><p>Added library for reading/writing Win32 resources including file versions</p></li>
<li><p>Managed custom action improvements:</p><ul>
<li><p>Simplified authoring and building -- new MakeSfxCA tool
automatically maps DLL entrypoints to CA methods.</p></li>
<li><p>Managed custom action DLLs now run in a separate process for
better reliability with respect to CLR versions, but still have
full access to the MSI session.</p></li>
</ul></li>
<li><p>Found and fixed many bugs with extensive unit test suite</p></li>
<li><p>LINQ to MSI ! (preview)</p></li>
</ul>
<p>Unfortunately, all these changes do mean that migrating tools and applications from
the previous release can be a moderate amount of work.</p>
<h3>Breaking Changes</h3>
<p>For the first time since v1.0, this release contains some major breaking
changes, due to a significant redesign and cleanup effort that has been a
long time coming. The overall purpose of the changes is to bring the class
libraries much closer to ship-quality.</p>
<ul>
<li><p>All libraries use a new namespace hierarchy
under <font face="Consolas, Courier New">Microsoft.Deployment</font>.
The new namespace aligns with the new project name, gives all the various
libraries an identity that makes them obviously related to the DTF project,
and mostly avoids "taking over" a namespace that might be rightfully owned
by the platform technology owner.</p></li>
<li><p>Assemblies are also renamed to follow namespaces.</p></li>
<li><p>A new unified compression framework forms the basis for the new ZIP
library and a redesigned CAB library. Additional archive formats can
be plugged into the framework. The stream-based compression APIs have
been redesigned to be more object-oriented and easier to use. The file-based
APIs are mostly unchanged from the old cabinet library, although some names
have changed in order to fit into the new unified framework.</p></li>
<li><p>Large parts of the WindowsInstaller library have been redesigned
to be more object-oriented and to better follow .NET Framework design
guidelines. And various APIs throughout the library have naming or other
changes for better consistency and to follow conventions and best
pratices as enforced by FxCop.</p></li>
<li><p>The WindowsInstaller APIs no longer make any attempt to mimic the
MSI COM automation interfaces. The naming and object patterns in the
automation interfaces often conflicted with with best practices for
.NET Framework class libraries. Since most people start using DTF
without having ever experienced MSI scripting, there is little
reason to match the scripting object model. Making the APIs more
consistent with .NET conventions will make them much easier to use
for people already experienced with the .NET Framework.</p></li>
<li><p>APIs in all class libraries use generics where appropriate, especially
the generic collection interfaces. This means .NET Framework 2.0 or later
is required.</p></li>
<li><p>The FilePatch library is missing from this release. An updated
and redesigned file-delta library is in development.</p></li>
</ul>
<h3>Other Changes</h3>
<ul>
<li><p>New MakeSfxCA tool for building managed custom action packages: In addition to
packaging the CA DLL and dependencies, it automatically detects managed CA methods
and generates corresponding unmanaged DLL entrypoints in the CA host DLL (SfxCA.dll),
where they are called by MSI. Previously it was necessary to either provide this
mapping in a CustomAction.config file, or live with the generic "ManagedCustomActionN"
names when authoring the CustomAction table in the MSI. For more info, see the
help topic on building managed custom actions.</p></li>
<li><p>Out-of-proc managed custom action DLLs:
When a managed custom action runs, it normally requests a specific major
version of the CLR via CustomAction.config. However in the previous implementation,
the request could be ignored if there was already a different version of the CLR
loaded into the MSI process, either from a previous custom action or by some other
means. (The CLR doesn't allow side-by-side versions within the same process.)
While there have been no reports of this issue causing setup failures in practice,
it may be only a matter of time, as new CLR versions keep coming out.</p>
<p>The redesigned native host for managed custom actions, SfxCA.dll, re-launches
itself in a separate process before loading the CLR and invoking the managed CA.
This ensures that the desired CLR version is always loaded, assuming it is available
on the system. It also sets up a named-pipe remoting channel between the two processes.
All session-related MSI API calls are routed through that channel, so that the
custom action has full access to the installer session just as if it were
running in-process.</p></li>
<li><p>The new zip compression library supports nearly all features of the zip
file format. This includes the ZIP64 extensions for archives greater than 4GB,
as well as disk-spanning capabilities. Zip encryption is not supported. The zip
library has been tested against a variety of third-party zip tools; please
report any issues with incompatible packages.</p>
<p>Currently only the basic DEFLATE compression algorithm is supported
(via System.IO.Compression.DeflateStream), and the compression level is not adjustable
when packing an archive. The zip file format has a mechanism for plugging in arbitrary
compression algorithms, and that capability is exposed: you can provide a Stream object
capable of compressing and decompressing bytes as an alternative to DeflateStream.</p></li>
<li><p>Added support for the few APIs new in MSI 4.0:</p>
<ul>
<li><font face="Consolas, Courier New">Installer.GetPatchFileList()</font></li>
<li><font face="Consolas, Courier New">InstallLogModes.RMFilesInUse</font></li>
<li><font face="Consolas, Courier New">ComponentAttributes.DisableRegistryReflection</font></li>
<li><font face="Consolas, Courier New">ControlAttributes.ElevationShield</font></li>
</ul>&nbsp;<br /></li>
<li><p>The documentation is now built with the
<a href="http://msdn2.microsoft.com/en-us/vstudio/bb608422.aspx" target="_blank">Sandcastle</a> doc build engine,
with help from the <a href="http://www.codeplex.com/SHFB" target="_blank">Sandcastle
Help File Builder</a>. (The old CHM was built with NDoc.)</p></li>
<li><p>The documentation includes detailed class diagrams for the
WindowsInstaller and Compression namespaces.</p></li>
<li><p>WindowsInstaller API doc topics now link straight to the corresponding
unmanaged MSI API topics in MSDN. If you know an unmanaged MSI API you want to
use but don't know the managed equivalent, you can search for it and find what
managed APIs link to it.</p></li>
<li><p>Unit tests cover about 90% of the Compression, Compression.Zip, and
Compression.Cab assemblies -- basically everything except some rare
error-handling cases.</p></li>
<li><p>Unit tests along with samples cover over 50% of the WindowsInstaller and
WindowsInstaller.Package assemblies (including custom action functionality). More
test cases are still being added.</p></li>
</ul>
<h3>Bugfixes</h3>
<p>In addition to the extensive cleanup due to redesigns and unit tests, the following
reported bugs have been fixed:</p>
<ul>
<li><p>Managed custom actions could in rare instances fail to load with error 183
(directory already exists)</p></li>
<li><p>Timestamps of files in a cabinet could be incorrectly offset based on the timezone.
(This was due to a behavior change in the DateTime class between .NET 1.1 and 2.0.)</p></li>
<li><p>Unicode file paths for cabbed files could be handled incorrectly in some cases</p></li>
<li><p>Installer.DetermineApplicablePatches just didn't work</p></li>
<li><p>InstallPackage.ApplyPatch couldn't handle applying multiple patches to the same layout</p></li>
</ul>
<h3>LINQ to MSI</h3>
<p><i>You'll never want to write MSI SQL again!</i></p>
<p>Language INtegrated Query is a new feature in .NET Framework 3.5 and C# 3.0. Through
a combination of intuitive language syntax and powerful query operations, LINQ provides
a whole new level of productivity for working with data in your code. While the .NET
Framework 3.5 provides LINQ capability for SQL databases and XML data, now you
can write LINQ queries to fetch and even update data in MSI databases!</p>
<p>Look at the following example:<br />
<pre><font face="Consolas, Courier New"> <font color="blue">var</font> actions = <font color="blue">from</font> a <font color="blue">in</font> db.InstallExecuteSequences
<font color="blue">join</font> ca <font color="blue">in</font> db.CustomActions <font color="blue">on</font> a.Action <font color="blue">equals</font> ca.Action
<font color="blue">where</font> ca.Type == CustomActionTypes.Dll
<font color="blue">orderby</font> a.Sequence
<font color="blue">select new</font> {
Name = a.Action,
Target = ca.Target,
Sequence = a.Sequence };
<font color="blue">foreach</font> (<font color="blue">var</font> a <font color="blue">in</font> actions)
{
Console.WriteLine(a);
}
</font></pre>
The query above gets automatically translated to MSI SQL:</p>
<p><font face="Consolas, Courier New">&nbsp;&nbsp;&nbsp;&nbsp;SELECT `InstallExecuteSequence`.`Action`,
`CustomAction`.`Target`, `InstallExecuteSequence`.`Sequence` FROM `InstallExecuteSequence`, `CustomAction`
WHERE `InstallExecuteSequence`.Action` = `CustomAction`.`Action` ORDER BY `InstallExecuteSequence`.`Sequence`</font></p>
<p>But the query is not executed until the <font face="Consolas, Courier New">foreach</font>
enumeration. Then records are fetched from the results incrementally as the enumeration progresses.
The objects fetched are actually of an anonymous type created there in the query with exactly
the desired fields. So the result of this code will be to print the Action, Target, and Sequence
of all Type 1 custom actions.</p>
<p>The query functionality is currently limited by the capabilities of the MSI SQL engine. For
example, a query can't use <font face="Consolas, Courier New">where (ca.Type &amp;
CustomActionTypes.Dll) != 0</font> because the bitwise-and operator is not supported by
MSI SQL. The preview version of LINQ to MSI will throw an exception for cases like that, but
the eventual goal is to have it automatically move the data and operation outside of MSI when
necessary, so that any arbitrary expressions are supported in the query.</p>
<p>Note there are no MSI handles (or <font face="Consolas, Courier New">IDisposable</font>s)
to worry about! Handles are all managed internally and closed deterministically. Also,
with the entity object model for common tables, the compiler will tell you if you get a
column name wrong or misspelled. The entity objects even support easy inserting, updating,
and deleting (not shown here).</p>
<p>For more examples, see the LinqTest project in the source. More documentation
is being written.</p>
<p>Obviously, LINQ to MSI requires .NET Framework 3.5. Everything else
in DTF requires only .NET Framework 2.0.</p>
<p><font color="red">Note: The LINQ functionality in this DTF release is of preview quality only
and should not be used in production. While there are unit tests covering a wide
variety of queries, using advanced queries outside what is covered by the tests
is likely to result in unexpected exceptions, and retrieved data might possibly be
incorrect or incomplete. An updated LINQ to MSI library is in development.</font></p>
<p>&nbsp;</p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,73 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Windows Installer Package File Manipulation Tool</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Windows Installer Package File Manipulation Tool</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="samples.htm">Samples</a> &gt;
<span class="nolink">WiFile</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p><pre><font face="Consolas, Courier New">Usage: WiFile.exe package.msi /l [filename,filename2,...]
Usage: WiFile.exe package.msi /x [filename,filename2,...]
Usage: WiFile.exe package.msi /u [filename,filename2,...]
Lists (/l), extracts (/x) or updates (/u) files in an MSI or MSM.
Files are extracted using their source path relative to the package.
Specified filenames do not include paths.
Filenames may be a pattern such as *.exe or file?.dll</font></pre>
</p>
<p><br/></p>
<h4>Example</h4>
<p>The most powerful use of WiFile.exe is to do a round-trip update of files in a
compressed MSI/MSM package. It works like this:<ol>
<li>Extract specific file(s) or all files from the package:
<tt>WiFile.exe package.msi /x *</tt></li>
<li>The files are now expanded into their directory structure. You can edit/update
the files however you like.</li>
<li>Update the package with the changed files: <tt>WiFile.exe package.msi /u *</tt>&nbsp;
This also updates the file metadata in the MSI including the file version, size, and hash.</li>
</ol></p>
<p><br/></p>
<h4>Notes</h4>
<ul>
<li><p>Also works with packages that have multiple and/or external cab(s).</p></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,114 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Writing Managed Custom Actions</title>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
<link rel="stylesheet" type="text/css" href="ms-help://Hx/HxRuntime/HxLink.css" />
</head>
<body>
<div id="control">
<span class="productTitle">Deployment Tools Foundation</span><br />
<span class="topicTitle">Writing Managed Custom Actions</span><br />
<div id="toolbar">
<span id="chickenFeet">
<a href="using.htm">Development Guide</a> &gt;
<a href="managedcas.htm">Managed CAs</a> &gt;
<span class="nolink">Writing CAs</span>
</span>
</div>
</div>
<div id="main">
<div id="header">
</div>
<div class="summary">
<p><b>Caveats</b></p>
<p>Before choosing to write a custom action in managed code instead of
traditional native C++ code, you should carefully consider the following:</p>
<ul>
<li><p>Obviously, it introduces a dependency on the .NET Framework. Your
MSI package should probably have a LaunchCondition to check for the presence
of the correct version of the .NET Framework before anything else happens.</p></li>
<li><p>If the custom action runs at uninstall time, then even the uninstall of
your product may fail if the .NET Framework is not present. This means a
user could run into a problem if they uninstall the .NET Framework before
your product.</p></li>
<li><p>A managed custom action should be configured to run against a specific
version of the .NET Framework, and that version should match the version your
actual product runs against. Allowing the version to "float" to the latest
installed .NET Framework is likely to lead to compatibility problems with
future versions. The .NET Framework provides side-by-side functionality for
good reason -- use it.</p></li>
</ul>
<p><br/></p>
<p><b>How To</b></p>
<ul>
<li><p>A custom action function needs to be declared as
<tt>public static</tt> (aka <tt>Public Shared</tt> in VB.NET). It takes one parameter which is
a <a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_Session.htm">Session</a> object, and returns a
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_ActionResult.htm">ActionResult</a> enumeration.</p>
<pre><font face="Consolas, Courier New"> [CustomAction]
<font color=blue>public</font> <font color=blue>static</font> ActionResult MyCustomAction(Session session)</font></pre><br />
<li><p>The function must have a
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_CustomActionAttribute.htm"
>CustomActionAttribute</a>, which enables it to be
linked to a proxy function. The attribute can take an optional
&quot;name&quot; parameter, which is the name of the entrypoint
that is exported from the custom action DLL.</p>
<li><p>Fill in MSI CustomAction table entries just like you
would for a normal type 1 native-DLL CA. Managed CAs can also work just
as well in deferred, rollback, and commit modes.</p>
<li><p>If the custom action function throws any kind of
Exception that isn't handled internally, then it will be caught by the proxy
function. The Exception message and stack trace will be printed to the
MSI log if logging is enabled, and the CA will return a failure code.</p>
<li><p>To be technically correct, any MSI handles obtained should be
closed before a custom action function exits -- otherwise a warning
gets printed to the log. The handle classes in the managed library
(<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_Database.htm">Database</a>,
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_View.htm">View</a>,
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_Record.htm">Record</a>,
<a href="DTFAPI.chm::/html/T_Microsoft_Deployment_WindowsInstaller_SummaryInfo.htm">SummaryInfo</a>)
all implement the IDisposable interface,
which makes them easily managed with C#'s <tt>using</tt>
statement. Alternatively, they can be closed in a finally block.
As a general rule, <i>methods</i> return new handle objects that should be
managed and closed by the user code, while <i>properties</i> only return a reference
to a prexisting handle object.</p></li>
<li><p>Don't forget to use a <a href="caconfig.htm">CustomAction.config</a> file to
specify what version of the .NET Framework the custom action should run against.</p></li>
</ul>
<p><br/></p>
<p><b>See also:</b></p>
<ul>
<li><a href="samplecas.htm">Sample C# Custom Actions</a></li>
<li><a href="caconfig.htm">Specifying the Runtime Version</a></li>
<li><a href="databases.htm">Working with MSI Databases</a></li>
<li><a href="buildingcas.htm">Building Managed Custom Actions</a></li>
<li><a href="debuggingcas.htm">Debugging Managed Custom Actions</a></li>
</ul>
<p><br/></p>
</div>
<div id="footer">
<p />
Send comments on this topic to <a id="HT_MailLink" href="mailto:wix-users%40lists.sourceforge.net?Subject=Deployment Tools Foundation Documentation">
wix-users@lists.sourceforge.net</a>
<script type="text/javascript">
var HT_mailLink = document.getElementById("HT_MailLink");
var HT_mailLinkText = HT_mailLink.innerHTML;
HT_mailLink.href += ": " + document.title;
HT_mailLink.innerHTML = HT_mailLinkText;
</script>
<p />
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,132 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<!-- Sitemap 1.0 -->
</HEAD><BODY>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Deployment Tools Foundation Overview">
<param name="Local" value="Content\about.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="What's New?">
<param name="Local" value="Content\whatsnew.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Change History">
<param name="Local" value="Content\history.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Dependencies">
<param name="Local" value="Content\dependencies.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Support/Bugs">
<param name="Local" value="Content\support.htm">
</OBJECT>
</LI>
</UL>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Deployment Tools Foundation Development Guide">
<param name="Local" value="Content\using.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Managed Custom Actions">
<param name="Local" value="Content\managedcas.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Writing Managed Custom Actions">
<param name="Local" value="Content\writingcas.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Specifying the Runtime Version">
<param name="Local" value="Content\caconfig.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Sample C# Custom Actions">
<param name="Local" value="Content\samplecas.htm">
</OBJECT>
</LI>
</UL>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Building Managed Custom Actions">
<param name="Local" value="Content\buildingcas.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Debugging Managed Custom Actions">
<param name="Local" value="Content\debuggingcas.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="InstallUtil Notes">
<param name="Local" value="Content\installutil.htm">
</OBJECT>
</LI>
</UL>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Working with MSI Databases">
<param name="Local" value="Content\databases.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Working with Cabinet Files">
<param name="Local" value="Content\cabs.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Working with Install Packages">
<param name="Local" value="Content\packages.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Sample Applications">
<param name="Local" value="Content\samples.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="MSI Inventory">
<param name="Local" value="Content\inventory.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="WiFile">
<param name="Local" value="Content\wifile.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="XPack">
<param name="Local" value="Content\cabpack.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="DDiff">
<param name="Local" value="Content\powerdiff.htm">
</OBJECT>
</LI>
</UL>
</LI>
</UL>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Deployment Tools Foundation Reference">
<param name="Local" value="DTFAPI.chm::/html/R_Project.htm">
</OBJECT>
<OBJECT type="text/sitemap">
<param name="Merge" value="DTFAPI.chm::/DTFAPI.hhc">
</OBJECT>
</LI>
</UL>
</BODY>
</HTML>

Просмотреть файл

@ -0,0 +1,126 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<!-- Sitemap 1.0 -->
</HEAD><BODY>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Deployment Tools Foundation Overview">
<param name="Local" value="Content\about.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="What's New?">
<param name="Local" value="Content\whatsnew.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Dependencies">
<param name="Local" value="Content\dependencies.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Sample Applications">
<param name="Local" value="Content\samples.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Inventory Sample Application">
<param name="Local" value="Content\inventory.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="WiFile Sample Tool">
<param name="Local" value="Content\wifile.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="CabPack Sample Tool">
<param name="Local" value="Content\cabpack.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="DDiff Sample Tool">
<param name="Local" value="Content\powerdiff.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Support/Bugs">
<param name="Local" value="Content\support.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Change History">
<param name="Local" value="Content\history.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Using Deployment Tools Foundation">
<param name="Local" value="Content\using.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Custom Actions">
<param name="Local" value="Content\managedcas.htm">
</OBJECT>
<UL>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Writing">
<param name="Local" value="Content\writingcas.htm">
</OBJECT>
</LI>
<LI>
<OBJECT type="text/sitemap">
<param name="Name" value="CustomAction.config">
<param name="Local" value="Content\caconfig.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Building">
<param name="Local" value="Content\buildingcas.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Debugging">
<param name="Local" value="Content\debuggingcas.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Samples">
<param name="Local" value="Content\samplecas.htm">
</OBJECT>
</LI>
</UL>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="InstallUtil">
<param name="Local" value="Content\installutil.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="CustomAction.config file">
<param name="Local" value="Content\caconfig.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Sample C# Custom Actions">
<param name="Local" value="Content\samplecas.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Databases, Working with">
<param name="Local" value="Content\databases.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Cabinets, Working with">
<param name="Local" value="Content\cabs.htm">
</OBJECT>
</LI>
<LI><OBJECT type="text/sitemap">
<param name="Name" value="Packages, Working with">
<param name="Local" value="Content\packages.htm">
</OBJECT>
</LI>
</UL>
</BODY></HTML>

Просмотреть файл

@ -0,0 +1,49 @@
[OPTIONS]
Auto Index=Yes
Compatibility=1.1 or later
Compiled file=DTF.chm
Contents file=DTF.hhc
Default Window=DTF
Default topic=Content\about.htm
Display compile progress=Yes
Error log file=DTFhelp.log
Full-text search=Yes
Index file=DTF.hhk
Language=0x409 English (United States)
Title=Deployment Tools Foundation
[WINDOWS]
DTF="Deployment Tools Foundation","DTF.hhc","DTF.hhk","Content\about.htm","Content\about.htm",,,,,0x22520,,0x384e,[143,72,937,601],,,,,,,0
[FILES]
styles\presentation.css
Content\about.htm
Content\whatsnew.htm
Content\dependencies.htm
Content\using.htm
DTF.hhc
DTF.hhk
Content\samples.htm
Content\support.htm
Content\history.htm
Content\inventory.htm
Content\wifile.htm
Content\cabpack.htm
Content\powerdiff.htm
Content\cabs.htm
Content\databases.htm
Content\packages.htm
Content\managedcas.htm
Content\samplecas.htm
Content\writingcas.htm
Content\buildingcas.htm
Content\debuggingcas.htm
Content\caproxy.htm
Content\caconfig.htm
Content\installutil.htm
[MERGE FILES]
DTFAPI.chm
[INFOTYPES]

Просмотреть файл

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="dtfguide.build" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<project name="dtfguide" default="dtfguide.inc" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
<description>
dtfref.build - Builds the Deployment Tools Foundation user-guide CHM.
</description>
<!--
//////////////////////////////////////////////////////////////////////////////////////////////////
// Properties
//////////////////////////////////////////////////////////////////////////////////////////////////
-->
<!-- Include the global build properties -->
<include buildfile="..\..\..\..\wix.include" unless="${property::exists('wix.properties.defined')}" />
<!-- Help tools directories -->
<property name="dir.hhw" value="${environment::get-variable('ProgramFiles(x86)')}\HTML Help Workshop" readonly="true" if="${environment::variable-exists('ProgramFiles(x86)')}" />
<property name="dir.hhw" value="${environment::get-variable('ProgramFiles')}\HTML Help Workshop" readonly="true" unless="${environment::variable-exists('ProgramFiles(x86)')}" />
<property name="hhw-found" value="${directory::exists(dir.hhw)}" readonly="true" />
<!-- dtfguide-specific properties -->
<property name="dir.src.dtfguide" value="${dir.wixroot.src}\dtf\Documents\Guide" readonly="true" />
<property name="dir.build.dtfguide" value="${dir.build.wix}\dtfguide" readonly="true" />
<!--
//////////////////////////////////////////////////////////////////////////////////////////////////
// Targets
//////////////////////////////////////////////////////////////////////////////////////////////////
-->
<!-- Build -->
<target name="dtfguide.build" description="Peforms a full rebuild (clean then build)" depends="dtfguide.clean dtfguide.inc">
</target>
<!-- Clean -->
<target name="dtfguide.clean" description="Cleans the build">
<delete dir="${dir.build.dtfguide}" />
<delete file="${dir.target.wix}\DTF.chm" />
</target>
<!-- Inc -->
<target name="dtfguide.inc" description="Performs an incremental build">
<if test="${not ship}">
<echo message="Skipping DTF user-guide CHM build because build flavor is not 'ship'." />
</if>
<if test="${not hhw-found}">
<echo message="Skipping DTF user-guide CHM build because HTML Help Workshop was not found at '${dir.hhw}'." />
</if>
<if test="${ship and hhw-found}">
<exec program="${dir.src.dtfguide}\hhc.bat" workingdir="${dir.src.dtfguide}" failonerror="true">
<arg file="${dir.hhw}\hhc.exe" />
<arg file="${dir.src.dtfguide}\dtf.hhp" />
</exec>
<move file="${dir.src.dtfguide}\DTFhelp.log" todir="${dir.build.dtfguide}" overwrite="true" />
<move file="${dir.src.dtfguide}\DTF.chm" todir="${dir.target.wix}" overwrite="true" />
</if>
</target>
</project>

Просмотреть файл

@ -0,0 +1 @@
@%1 %2 & if not errorlevel 1 exit /b 1

Просмотреть файл

@ -0,0 +1,394 @@
/* page style */
body {
margin: 0;
background-color: #FFFFFF;
padding: 0;
font-size: 80%;
font-family: verdana, sans-serif;
color: #000000;
}
table {
/* this is a trick to force tables to inherit the body font size */
font-size: 100%;
}
/* non-scrolling (control) region style */
div#control {
margin: 0;
background-color: #D4DFFF;
padding: 4px;
width: 100%;
border-bottom-color: #C8CDDE;
border-bottom-style: solid;
border-bottom-width: 1;
}
span.productTitle {
font-size: 80%;
}
span.topicTitle {
font-size: 140%;
font-weight: bold;
color: #003399;
}
span#chickenFeet {
float: left;
}
span#languageFilter {
float: right;
}
/* scrolling (content) region style */
div#main {
margin: 0;
padding: 1em;
width: 100%;
clear: both;
}
/* sections */
div#header {
font-size: 70%;
color: #666666;
margin-bottom: 0.5em;
}
div.section {
margin-bottom: 1em;
}
div.sectionTitle {
display: inline;
font-size: 120%;
font-weight: bold;
color: #003399;
}
div.sectionContent {
margin-top: 0.2em;
}
span.subsectionTitle {
font-weight: bold;
}
div#footer {
margin-top: 1em;
border-top: thin solid #003399;
padding-top: 0.5em;
}
/* authored content (block) */
p {
margin-top: 0;
margin-bottom: 1em;
}
dl {
margin-top: 0;
margin-bottom: 1em;
}
div.code {
clear: both;
width: 100%;
background: #F7F7FF;
padding: 0.4em;
font-family: "Andale Mono";
/* font-family: "Courier New"; */
/* font-family: "This is not a monospace font", monospace; */
font-size: inherit;
margin-bottom: 1em;
}
pre {
margin: 0;
padding: 0;
}
table.authoredTable {
table-layout: fixed;
width: 100%;
margin-bottom: 1em;
}
table.authoredTable th {
border-bottom-color: #C8CDDE;
border-bottom-style: solid;
border-bottom-width: 1;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
}
table.authoredTable td {
border-bottom-style: solid;
border-bottom-color: #C8CDDE;
border-bottom-width: 1px;
background: #F7F7FF;
padding: 0.2em;
vertical-align: top;
}
div.alert {
border: 1px solid #C8CDDE;
background: #F7F7FF;
}
div.media {
text-align: center;
margin-bottom: 1em;
}
/* authored content (inline) */
span.keyword {
font-weight: bold;
}
span.code {
font-family: "Andale Mono", "Courier New", Courier, monospace;
}
/* auto-generated controls */
div.langTabs {
width: 100%;
}
div.langTab {
float: left;
width: 16%;
border-top: 1px solid #C8CDDE;
border-left: 1px solid #C8CDDE;
border-right: 1px solid #C8CDDE;
background: #F7F7FF;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: normal;
}
div.activeLangTab {
float: left;
width: 16%;
border-top: 1px solid #C8CDDE;
border-left: 1px solid #C8CDDE;
border-right: 1px solid #C8CDDE;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
}
table.members {
table-layout: fixed;
width: 100%;
}
table.members th.iconColumn {
width: 60px;
}
table.members th.nameColumn {
width: 33%;
}
table.members th.descriptionColumn {
width: 66%;
}
table.members th {
border-bottom-color: #C8CDDE;
border-bottom-style: solid;
border-bottom-width: 1;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
}
table.members td {
border-bottom-style: solid;
border-bottom-color: #C8CDDE;
border-bottom-width: 1px;
background: #F7F7FF;
padding: 0.2em;
vertical-align: top;
overflow: hidden;
}
table.exceptions {
table-layout: fixed;
width: 100%;
}
table.exceptions th.exceptionNameColumn {
width: 33%;
}
table.exceptions th.exceptionConditionColumn {
width: 66%;
}
table.exceptions th {
border-bottom-color: #C8CDDE;
border-bottom-style: solid;
border-bottom-width: 1;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
}
table.exceptions td {
border-bottom-style: solid;
border-bottom-color: #C8CDDE;
border-bottom-width: 1px;
background: #F7F7FF;
padding: 0.2em;
vertical-align: top;
}
table.permissions {
table-layout: fixed;
width: 100%;
}
table.permissions th.permissionNameColumn {
width: 33%;
}
table.permissions th.permissionConditionColumn {
width: 66%;
}
table.permissions th {
border-bottom-color: #C8CDDE;
border-bottom-style: solid;
border-bottom-width: 1;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
}
table.permissions td {
border-bottom-style: solid;
border-bottom-color: #C8CDDE;
border-bottom-width: 1px;
background: #F7F7FF;
padding: 0.2em;
vertical-align: top;
}
span.obsolete {
color: red;
}
span.cs {
display: inline;
}
span.vb {
display: none;
}
span.cpp {
display: none;
}
/* syntax styling */
div.code span.identifier {
font-size: 120%;
font-weight: bold;
}
div.code span.keyword {
color: green;
}
div.code span.parameter {
font-style: italic;
color: purple;
}
div.code span.literal {
color: purple;
}
div.code span.comment {
color: red;
}
span.foreignPhrase {
font-style: italic;
}
span.placeholder {
font-style: italic;
}
a {
color: blue;
font-weight: bold;
text-decoration: none;
}
MSHelp\:link {
color: blue;
font-weight: bold;
hoverColor: #3366ff;
}
span.nolink {
font-weight: bold;
}
table.filter {
table-layout: fixed;
}
tr.tabs td.tab {
width: 10em;
background: #F7F7FF;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: normal;
overflow: hidden;
cursor: pointer;
}
tr.tabs td.activeTab {
width: 10em;
background: #EFEFF7;
padding: 0.2em;
text-align: left;
color: #000066;
font-weight: bold;
overflow: hidden;
}
td.line {
background: #EFEFF7;
}

Просмотреть файл

@ -0,0 +1,13 @@
<html>
<head>
<title>Class Diagram: Microsoft.Deployment.Compression</title>
</head>
<body>
<h3><font face="Verdana">Microsoft.Deployment.Compression Namespace</font></h3>
<img src="Compression1.png" width="870" height="596" border="0" />
<img src="Compression2.png" width="870" height="596" border="0" />
</body>
</html>

Двоичные данные
src/DTF/Documents/Reference/Compression1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 77 KiB

Двоичные данные
src/DTF/Documents/Reference/Compression2.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 67 KiB

Просмотреть файл

@ -0,0 +1,14 @@
<html>
<head>
<title>Class Diagram: Microsoft.Deployment.WindowsInstaller</title>
</head>
<body>
<h3><font face="Verdana">Microsoft.Deployment.WindowsInstaller Namespace</font></h3>
<img src="WindowsInstaller1.png" width="1136" height="1247" border="0" />
<img src="WindowsInstaller2.png" width="1108" height="1247" border="0" />
<img src="WindowsInstaller3.png" width="866" height="1247" border="0" />
</body>
</html>

Двоичные данные
src/DTF/Documents/Reference/WindowsInstaller1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 203 KiB

Двоичные данные
src/DTF/Documents/Reference/WindowsInstaller2.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 176 KiB

Двоичные данные
src/DTF/Documents/Reference/WindowsInstaller3.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 118 KiB

Просмотреть файл

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="dtfref.build" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<project name="dtfref" default="dtfref.inc" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
<description>
dtfref.build - Builds the Deployment Tools Foundation reference CHM.
</description>
<!--
//////////////////////////////////////////////////////////////////////////////////////////////////
// Properties
//////////////////////////////////////////////////////////////////////////////////////////////////
-->
<!-- Include the global build properties -->
<include buildfile="..\..\..\..\wix.include" unless="${property::exists('wix.properties.defined')}" />
<!-- Help tools directories -->
<property name="dir.sandcastle" value="${dir.externalroot}\Sandcastle" readonly="true" />
<property name="dir.sandcastlebuilder" value="${dir.externalroot}\SandcastleBuilder" readonly="true" />
<property name="dir.hhw" value="${environment::get-variable('ProgramFiles(x86)')}\HTML Help Workshop" readonly="true" if="${environment::variable-exists('ProgramFiles(x86)')}" />
<property name="dir.hhw" value="${environment::get-variable('ProgramFiles')}\HTML Help Workshop" readonly="true" unless="${environment::variable-exists('ProgramFiles(x86)')}" />
<property name="sandcastle-found" value="${directory::exists(dir.sandcastle)}" readonly="true" />
<property name="sandcastlebuilder-found" value="${directory::exists(dir.sandcastlebuilder)}" readonly="true" />
<property name="hhw-found" value="${directory::exists(dir.hhw)}" readonly="true" />
<!-- dtfref-specific properties -->
<property name="dir.src.dtfref" value="${dir.wixroot.src}\dtf\Documents\Reference" readonly="true" />
<property name="dir.target.dtfref" value="${dir.target.project}\dtfref" readonly="true" />
<property name="dir.build.dtfref" value="${dir.build.project}\dtfref" readonly="true" />
<!--
//////////////////////////////////////////////////////////////////////////////////////////////////
// Targets
//////////////////////////////////////////////////////////////////////////////////////////////////
-->
<!-- Build -->
<target name="dtfref.build" description="Peforms a full rebuild (clean then build)" depends="dtfref.clean dtfref.inc">
</target>
<!-- Clean -->
<target name="dtfref.clean" description="Cleans the build">
<delete dir="${dir.build.dtfref}" />
<delete dir="${dir.target.dtfref}" />
<delete file="${dir.target.wix}\DTFAPI.chm" />
</target>
<!-- Inc -->
<target name="dtfref.inc" description="Performs an incremental build">
<if test="${not ship}">
<echo message="Skipping DTF reference CHM build because build flavor is not 'ship'." />
</if>
<if test="${not hhw-found}">
<echo message="Skipping DTF reference CHM build because HTML Help Workshop was not found at '${dir.hhw}'." />
</if>
<if test="${not sandcastle-found}">
<echo message="Skipping DTF reference CHM build because Sandcastle was not found at '${dir.sandcastle}'." />
</if>
<if test="${not sandcastlebuilder-found}">
<echo message="Skipping DTF reference CHM build because Sandcastle Builder was not found at '${dir.sandcastlebuilder}'." />
</if>
<if test="${ship and hhw-found and sandcastle-found and sandcastlebuilder-found}">
<exec program="msbuild.exe" basedir="${wix.settings.msbuildframework}" failonerror="true">
<arg value="/property:Configuration=Debug" if="${debug}" />
<arg value="/property:Configuration=Release" if="${ship}" />
<arg value="/property:SHFBROOT=${dir.sandcastlebuilder}" />
<arg value="/property:OutputPath=${dir.target.dtfref}" />
<arg value="/property:WorkingPath=${dir.build.dtfref}" />
<arg value="/property:SandcastlePath=${dir.sandcastle}" />
<arg value="/property:HtmlHelp1xCompilerPath=${dir.hhw}" />
<arg value="/property:DirTargetWix=${dir.target.wix}" />
<arg value="/verbosity:${msbuildverbosity}" />
<arg value="/target:Rebuild" />
<arg file="${dir.src.dtfref}\dtfref.shfbproj" />
</exec>
<copy file="${dir.target.dtfref}\DTFAPI.chm" todir="${dir.target.wix}" />
</if>
</target>
</project>

Просмотреть файл

@ -0,0 +1,102 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<!-- The configuration and platform will be used to determine which
assemblies to include from solution and project documentation
sources -->
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{27c20359-3910-423d-8058-6403935b98c6}</ProjectGuid>
<SHFBSchemaVersion>1.8.0.3</SHFBSchemaVersion>
<!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual
Studio adds them anyway -->
<AssemblyName>Documentation</AssemblyName>
<RootNamespace>Documentation</RootNamespace>
<Name>Documentation</Name>
<!-- SHFB properties -->
<HtmlHelpName>DTFAPI</HtmlHelpName>
<ProjectSummary>
</ProjectSummary>
<MissingTags>Namespace, TypeParameter</MissingTags>
<VisibleItems>InheritedMembers, InheritedFrameworkMembers, Protected, ProtectedInternalAsProtected, SealedProtected</VisibleItems>
<!--
<OutputPath>.\</OutputPath>
<HtmlHelp1xCompilerPath>
</HtmlHelp1xCompilerPath>
<HtmlHelp2xCompilerPath>
</HtmlHelp2xCompilerPath>
<SandcastlePath>
</SandcastlePath>
-->
<WorkingPath>..\obj\</WorkingPath>
<FrameworkVersion>2.0.50727</FrameworkVersion>
<RootNamespaceTitle>Deployment Tools Foundation Namespaces</RootNamespaceTitle>
<HelpTitle>Deployment Tools Foundation</HelpTitle>
<FeedbackEMailAddress>wix-users%40lists.sourceforge.net</FeedbackEMailAddress>
<FooterText>&amp;lt%3bscript src=&amp;quot%3bhelplink.js&amp;quot%3b&amp;gt%3b&amp;lt%3b/script&amp;gt%3b</FooterText>
<PresentationStyle>Prototype</PresentationStyle>
<NamingMethod>MemberName</NamingMethod>
<NamespaceSummaries>
<NamespaceSummaryItem name="(global)" isDocumented="False" xmlns="" />
<NamespaceSummaryItem name="Microsoft.Deployment.Compression" isDocumented="True" xmlns="">Framework for archive packing and unpacking.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.Compression.Cab" isDocumented="True" xmlns="">Implements cabinet archive packing and unpacking.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.Compression.Zip" isDocumented="True" xmlns="">Implements zip archive packing and unpacking.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.Resources" isDocumented="True" xmlns="">Classes for reading and writing resource data in executable files.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.WindowsInstaller" isDocumented="True" xmlns="">Complete class library for the Windows Installer APIs.</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.WindowsInstaller.Linq" isDocumented="True" xmlns="">LINQ extensions for querying Windows Installer databases (experimental).</NamespaceSummaryItem>
<NamespaceSummaryItem name="Microsoft.Deployment.WindowsInstaller.Linq.Entities" isDocumented="False" xmlns="" />
<NamespaceSummaryItem name="Microsoft.Deployment.WindowsInstaller.Package" isDocumented="True" xmlns="">Extended classes for working with Windows Installer installation and patch packages.</NamespaceSummaryItem>
</NamespaceSummaries>
<DocumentationSources>
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.Cab.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.Cab.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.Zip.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Compression.Zip.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Resources.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.Resources.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.Package.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.Package.xml" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.Linq.dll" xmlns="" />
<DocumentationSource sourceFile="$(DirTargetWix)\Microsoft.Deployment.WindowsInstaller.Linq.xml" xmlns="" />
</DocumentationSources>
</PropertyGroup>
<!-- There are no properties for these groups. AnyCPU needs to appear in
order for Visual Studio to perform the build. The others are optional
common platform types that may appear. -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win32' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win32' ">
</PropertyGroup>
<ItemGroup>
<Content Include="helplink.js" />
<Content Include="Compression2.png" />
<Content Include="Compression1.png" />
<Content Include="Compression.htm" />
<Content Include="WindowsInstaller.htm" />
<Content Include="WindowsInstaller3.png" />
<Content Include="WindowsInstaller2.png" />
<Content Include="WindowsInstaller1.png" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<Reference Include="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</ItemGroup>
<!-- Import the SHFB build targets -->
<Import Project="$(SHFBROOT)\SandcastleHelpFileBuilder.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,194 @@
//---------------------------------------------------------------------
// <copyright file="helplink.js" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Fix MSDN API links in the DTF documentation pages.
// </summary>
//---------------------------------------------------------------------
FixHelpLinks();
function GetHelpCode(apiName)
{
switch (apiName.toLowerCase())
{
case "msiadvertiseproduct": return 370056;
case "msiadvertiseproductex": return 370057;
case "msiapplymultiplepatches": return 370059;
case "msiapplypatch": return 370060;
case "msibegintransaction": return 736312;
case "msiclosehandle": return 370067;
case "msicollectuserinfo": return 370068;
case "msiconfigurefeature": return 370069;
case "msiconfigureproduct": return 370070;
case "msiconfigureproductex": return 370071;
case "msicreaterecord": return 370072;
case "msicreatetransformsummaryinfo": return 370073;
case "msidatabaseapplytransform": return 370074;
case "msidatabasecommit": return 370075;
case "msidatabaseexport": return 370076;
case "msidatabasegeneratetransform": return 370077;
case "msidatabasegetprimarykeys": return 370078;
case "msidatabaseimport": return 370079;
case "msidatabaseistablepersistent": return 370080;
case "msidatabasemerge": return 370081;
case "msidatabaseopenview": return 370082;
case "msidetermineapplicablepatches": return 370084;
case "msideterminepatchsequence": return 370085;
case "msidoaction": return 370090;
case "msienablelog": return 370091;
case "msiendtransaction": return 736318;
case "msienumclients": return 370094;
case "msienumcomponentcosts": return 370095;
case "msienumcomponentqualifiers": return 370096;
case "msienumcomponents": return 370097;
case "msienumfeatures": return 370098;
case "msienumpatches": return 370099;
case "msienumpatchesex": return 370100;
case "msienumproducts": return 370101;
case "msienumproductsex": return 370102;
case "msienumrelatedproducts": return 370103;
case "msievaluatecondition": return 370104;
case "msiextractpatchxmldata": return 370105;
case "msiformatrecord": return 370109;
case "msigetactivedatabase": return 370110;
case "msigetcomponentpath": return 370112;
case "msigetcomponentstate": return 370113;
case "msigetdatabasestate": return 370114;
case "msigetfeaturecost": return 370115;
case "msigetfeatureinfo": return 370116;
case "msigetfeaturestate": return 370117;
case "msigetfeatureusage": return 370118;
case "msigetfeaturevalidstates": return 370119;
case "msigetfilehash": return 370120;
case "msigetfileversion": return 370122;
case "msigetlanguage": return 370123;
case "msigetlasterrorrecord": return 370124;
case "msigetmode": return 370125;
case "msigetpatchfilelist": return 370126;
case "msigetpatchinfo": return 370127;
case "msigetpatchinfoex": return 370128;
case "msigetproductcode": return 370129;
case "msigetproductinfo": return 370130;
case "msigetproductinfoex": return 370131;
case "msigetproductinfofromscript": return 370132;
case "msigetproductproperty": return 370133;
case "msigetproperty": return 370134;
case "msigetshortcuttarget": return 370299;
case "msigetsourcepath": return 370300;
case "msigetsummaryinformation": return 370301;
case "msigettargetpath": return 370303;
case "msiinstallmissingcomponent": return 370311;
case "msiinstallmissingfile": return 370313;
case "msiinstallproduct": return 370315;
case "msijointransaction": return 736319;
case "msilocatecomponent": return 370320;
case "msinotifysidchange": return 370328;
case "msiopendatabase": return 370338;
case "msiopenpackage": return 370339;
case "msiopenpackageex": return 370340;
case "msiopenproduct": return 370341;
case "msiprocessadvertisescript": return 370353;
case "msiprocessmessage": return 370354;
case "msiprovideassembly": return 370355;
case "msiprovidecomponent": return 370356;
case "msiprovidequalifiedcomponent": return 370357;
case "msiprovidequalifiedcomponentex":return 370358;
case "msiquerycomponnetstate": return 370360;
case "msiqueryfeaturestate": return 370361;
case "msiqueryfeaturestateex": return 370362;
case "msiqueryproductstate": return 370363;
case "msirecordcleardata": return 370364;
case "msirecorddatasize": return 370365;
case "msirecordgetfieldcount": return 370366;
case "msirecordgetinteger": return 370367;
case "msirecordgetstring": return 370368;
case "msirecordisnull": return 370369;
case "msirecordreadstream": return 370370;
case "msirecordsetinteger": return 370371;
case "msirecordsetstream": return 370372;
case "msirecordsetstring": return 370373;
case "msireinstallfeature": return 370374;
case "msireinstallproduct": return 370375;
case "msiremovepatches": return 370376;
case "msisequence": return 370382;
case "msisetcomponentstate": return 370383;
case "msisetexternalui": return 370384;
case "msisetexternaluirecord": return 370385;
case "msisetfeatureattributes": return 370386;
case "msisetfeaturestate": return 370387;
case "msisetinstalllevel": return 370388;
case "msisetinternalui": return 370389;
case "msisetmode": return 370390;
case "msisetproperty": return 370391;
case "msisettargetpath": return 370392;
case "msisourcelistaddmediadisk": return 370394;
case "msisourcelistaddsource": return 370395;
case "msisourcelistaddsourceex": return 370396;
case "msisourcelistclearall": return 370397;
case "msisourcelistclearallex": return 370398;
case "msisourcelistclearmediadisk": return 370399;
case "msisourcelistclearsource": return 370401;
case "msisourcelistenummediadisks": return 370402;
case "msisourcelistenumsources": return 370403;
case "msisourcelistforceresolution": return 370404;
case "msisourcelistforceresolutionex":return 370405;
case "msisourcelistgetinfo": return 370406;
case "msisourcelistsetinfo": return 370407;
case "msisummaryinfogetproperty": return 370409;
case "msisummaryinfopersist": return 370490;
case "msisummaryinfosetproperty": return 370491;
case "msiusefeature": return 370502;
case "msiusefeatureex": return 370503;
case "msiverifydiskspace": return 370506;
case "msiverifypackage": return 370508;
case "msiviewexecute": return 370513;
case "msiviewfetch": return 370514;
case "msiviewgetcolumninfo": return 370516;
case "msiviewgeterror": return 370518;
case "msiviewmodify": return 370519;
case "productid": return 370855;
default:
return 0;
}
}
function GetHelpLink(apiName)
{
var helpCode = GetHelpCode(apiName);
if (helpCode != 0)
{
// Found a direct link!
var prefix = (helpCode < 500000 ? "aa" : "bb");
return "http://msdn2.microsoft.com/en-us/library/" + prefix + helpCode + ".aspx";
}
else
{
// This link works, but goes through an annoying 5-sec redirect page.
return "http://msdn.microsoft.com/library/en-us/msi/setup/" + apiName.toLowerCase() + ".asp";
}
}
// Change any MSI API help links from indirect MSDN references to direct references.
function FixHelpLinks()
{
var msiLinkRegex = /msdn\.microsoft\.com\/library\/en-us\/msi\/setup\/([a-z]+)\.asp/i;
var links = document.body.all.tags("a");
var i;
for (i = 0; i < links.length; i++)
{
var linkElem = links(i);
var match = msiLinkRegex.exec(linkElem.href);
if (match)
{
var apiName = match[1];
linkElem.href = GetHelpLink(apiName);
linkElem.target = "_blank";
linkElem.title = "MSDN Library";
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
using System;
using System.Resources;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
[assembly: AssemblyDescription("Managed libraries for cabinet archive packing and unpacking")]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
// SECURITY: The UnmanagedCode assertions in the cabinet classes are safe, because the
// assertions are not propogated through calls to the provided callbacks. So there
// is no way that a partially-trusted malicious client could trick a trusted cabinet
// class into executing its own unmanaged code.
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion=true, UnmanagedCode=true)]
// SECURITY: Review carefully!
// This assembly is designed so that partially trusted callers should be able to
// do cabinet compression and extraction in a file path where they have limited
// file I/O permission. Or they can even do in-memory compression and extraction
// with absolutely no file I/O permission.
[assembly: AllowPartiallyTrustedCallers]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Deployment.Compression.Cab")]

Просмотреть файл

@ -0,0 +1,174 @@
//---------------------------------------------------------------------
// <copyright file="CabEngine.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.Collections.Generic;
/// <summary>
/// Engine capable of packing and unpacking archives in the cabinet format.
/// </summary>
public class CabEngine : CompressionEngine
{
private CabPacker packer;
private CabUnpacker unpacker;
/// <summary>
/// Creates a new instance of the cabinet engine.
/// </summary>
public CabEngine()
: base()
{
}
/// <summary>
/// Disposes of resources allocated by the cabinet engine.
/// </summary>
/// <param name="disposing">If true, the method has been called directly
/// or indirectly by a user's code, so managed and unmanaged resources
/// will be disposed. If false, the method has been called by the runtime
/// from inside the finalizer, and only unmanaged resources will be
/// disposed.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (packer != null)
{
packer.Dispose();
packer = null;
}
if (unpacker != null)
{
unpacker.Dispose();
unpacker = null;
}
}
base.Dispose(disposing);
}
private CabPacker Packer
{
get
{
if (this.packer == null)
{
this.packer = new CabPacker(this);
}
return this.packer;
}
}
private CabUnpacker Unpacker
{
get
{
if (this.unpacker == null)
{
this.unpacker = new CabUnpacker(this);
}
return this.unpacker;
}
}
/// <summary>
/// Creates a cabinet or chain of cabinets.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of cabinet and file streams.</param>
/// <param name="files">The paths of the files in the archive (not
/// external file paths).</param>
/// <param name="maxArchiveSize">The maximum number of bytes for one
/// cabinet before the contents are chained to the next cabinet, or zero
/// for unlimited cabinet size.</param>
/// <exception cref="ArchiveException">The cabinet could not be
/// created.</exception>
/// <remarks>
/// The stream context implementation may provide a mapping from the
/// file paths within the cabinet to the external file paths.
/// <para>Smaller folder sizes can make it more efficient to extract
/// individual files out of large cabinet packages.</para>
/// </remarks>
public override void Pack(
IPackStreamContext streamContext,
IEnumerable<string> files,
long maxArchiveSize)
{
this.Packer.CompressionLevel = this.CompressionLevel;
this.Packer.UseTempFiles = this.UseTempFiles;
this.Packer.Pack(streamContext, files, maxArchiveSize);
}
/// <summary>
/// Checks whether a Stream begins with a header that indicates
/// it is a valid cabinet file.
/// </summary>
/// <param name="stream">Stream for reading the cabinet file.</param>
/// <returns>True if the stream is a valid cabinet file
/// (with no offset); false otherwise.</returns>
public override bool IsArchive(Stream stream)
{
return this.Unpacker.IsArchive(stream);
}
/// <summary>
/// Gets information about files in a cabinet or cabinet chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of cabinet and file streams.</param>
/// <param name="fileFilter">A predicate that can determine
/// which files to process, optional.</param>
/// <returns>Information about files in the cabinet stream.</returns>
/// <exception cref="ArchiveException">The cabinet provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public override IList<ArchiveFileInfo> GetFileInfo(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
return this.Unpacker.GetFileInfo(streamContext, fileFilter);
}
/// <summary>
/// Extracts files from a cabinet or cabinet chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of cabinet and file streams.</param>
/// <param name="fileFilter">An optional predicate that can determine
/// which files to process.</param>
/// <exception cref="ArchiveException">The cabinet provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public override void Unpack(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
this.Unpacker.Unpack(streamContext, fileFilter);
}
internal void ReportProgress(ArchiveProgressEventArgs e)
{
base.OnProgress(e);
}
}
}

Просмотреть файл

@ -0,0 +1,166 @@
//---------------------------------------------------------------------
// <copyright file="CabException.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.Resources;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.Serialization;
/// <summary>
/// Exception class for cabinet operations.
/// </summary>
[Serializable]
public class CabException : ArchiveException
{
private static ResourceManager errorResources;
private int error;
private int errorCode;
/// <summary>
/// Creates a new CabException with a specified error message and a reference to the
/// inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If the
/// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception
/// is raised in a catch block that handles the inner exception.</param>
public CabException(string message, Exception innerException)
: this(0, 0, message, innerException) { }
/// <summary>
/// Creates a new CabException with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public CabException(string message)
: this(0, 0, message, null) { }
/// <summary>
/// Creates a new CabException.
/// </summary>
public CabException()
: this(0, 0, null, null) { }
internal CabException(int error, int errorCode, string message, Exception innerException)
: base(message, innerException)
{
this.error = error;
this.errorCode = errorCode;
}
internal CabException(int error, int errorCode, string message)
: this(error, errorCode, message, null) { }
/// <summary>
/// Initializes a new instance of the CabException class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected CabException(SerializationInfo info, StreamingContext context) : base(info, context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
this.error = info.GetInt32("cabError");
this.errorCode = info.GetInt32("cabErrorCode");
}
/// <summary>
/// Gets the FCI or FDI cabinet engine error number.
/// </summary>
/// <value>A cabinet engine error number, or 0 if the exception was
/// not related to a cabinet engine error number.</value>
public int Error
{
get
{
return this.error;
}
}
/// <summary>
/// Gets the Win32 error code.
/// </summary>
/// <value>A Win32 error code, or 0 if the exception was
/// not related to a Win32 error.</value>
public int ErrorCode
{
get
{
return this.errorCode;
}
}
internal static ResourceManager ErrorResources
{
get
{
if (errorResources == null)
{
errorResources = new ResourceManager(
typeof(CabException).Namespace + ".Errors",
typeof(CabException).Assembly);
}
return errorResources;
}
}
/// <summary>
/// Sets the SerializationInfo with information about the exception.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
info.AddValue("cabError", this.error);
info.AddValue("cabErrorCode", this.errorCode);
base.GetObjectData(info, context);
}
internal static string GetErrorMessage(int error, int errorCode, bool extracting)
{
const int FCI_ERROR_RESOURCE_OFFSET = 1000;
const int FDI_ERROR_RESOURCE_OFFSET = 2000;
int resourceOffset = (extracting ? FDI_ERROR_RESOURCE_OFFSET : FCI_ERROR_RESOURCE_OFFSET);
string msg = CabException.ErrorResources.GetString(
(resourceOffset + error).ToString(CultureInfo.InvariantCulture.NumberFormat),
CultureInfo.CurrentCulture);
if (msg == null)
{
msg = CabException.ErrorResources.GetString(
resourceOffset.ToString(CultureInfo.InvariantCulture.NumberFormat),
CultureInfo.CurrentCulture);
}
if (errorCode != 0)
{
const string GENERIC_ERROR_RESOURCE = "1";
string msg2 = CabException.ErrorResources.GetString(GENERIC_ERROR_RESOURCE, CultureInfo.CurrentCulture);
msg = String.Format(CultureInfo.InvariantCulture, "{0} " + msg2, msg, errorCode);
}
return msg;
}
}
}

Просмотреть файл

@ -0,0 +1,153 @@
//---------------------------------------------------------------------
// <copyright file="CabFileInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Permissions;
/// <summary>
/// Object representing a compressed file within a cabinet package; provides operations for getting
/// the file properties and extracting the file.
/// </summary>
[Serializable]
public class CabFileInfo : ArchiveFileInfo
{
private int cabFolder;
/// <summary>
/// Creates a new CabinetFileInfo object representing a file within a cabinet in a specified path.
/// </summary>
/// <param name="cabinetInfo">An object representing the cabinet containing the file.</param>
/// <param name="filePath">The path to the file within the cabinet. Usually, this is a simple file
/// name, but if the cabinet contains a directory structure this may include the directory.</param>
public CabFileInfo(CabInfo cabinetInfo, string filePath)
: base(cabinetInfo, filePath)
{
if (cabinetInfo == null)
{
throw new ArgumentNullException("cabinetInfo");
}
this.cabFolder = -1;
}
/// <summary>
/// Creates a new CabinetFileInfo object with all parameters specified,
/// used internally when reading the metadata out of a cab.
/// </summary>
/// <param name="filePath">The internal path and name of the file in the cab.</param>
/// <param name="cabFolder">The folder number containing the file.</param>
/// <param name="cabNumber">The cabinet number where the file starts.</param>
/// <param name="attributes">The stored attributes of the file.</param>
/// <param name="lastWriteTime">The stored last write time of the file.</param>
/// <param name="length">The uncompressed size of the file.</param>
internal CabFileInfo(
string filePath,
int cabFolder,
int cabNumber,
FileAttributes attributes,
DateTime lastWriteTime,
long length)
: base(filePath, cabNumber, attributes, lastWriteTime, length)
{
this.cabFolder = cabFolder;
}
/// <summary>
/// Initializes a new instance of the CabinetFileInfo class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected CabFileInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.cabFolder = info.GetInt32("cabFolder");
}
/// <summary>
/// Sets the SerializationInfo with information about the archive.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data.</param>
/// <param name="context">The StreamingContext that contains contextual information
/// about the source or destination.</param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("cabFolder", this.cabFolder);
}
/// <summary>
/// Gets or sets the cabinet that contains this file.
/// </summary>
/// <value>
/// The CabinetInfo instance that retrieved this file information -- this
/// may be null if the CabinetFileInfo object was returned directly from a
/// stream.
/// </value>
public CabInfo Cabinet
{
get
{
return (CabInfo) this.Archive;
}
}
/// <summary>
/// Gets the full path of the cabinet that contains this file.
/// </summary>
/// <value>The full path of the cabinet that contains this file.</value>
public string CabinetName
{
get
{
return this.ArchiveName;
}
}
/// <summary>
/// Gets the number of the folder containing this file.
/// </summary>
/// <value>The number of the cabinet folder containing this file.</value>
/// <remarks>A single folder or the first folder of a cabinet
/// (or chain of cabinets) is numbered 0.</remarks>
public int CabinetFolderNumber
{
get
{
if (this.cabFolder < 0)
{
this.Refresh();
}
return this.cabFolder;
}
}
/// <summary>
/// Refreshes the information in this object with new data retrieved
/// from an archive.
/// </summary>
/// <param name="newFileInfo">Fresh instance for the same file just
/// read from the archive.</param>
/// <remarks>
/// This implementation refreshes the <see cref="CabinetFolderNumber"/>.
/// </remarks>
protected override void Refresh(ArchiveFileInfo newFileInfo)
{
base.Refresh(newFileInfo);
this.cabFolder = ((CabFileInfo) newFileInfo).cabFolder;
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
//---------------------------------------------------------------------
// <copyright file="CabInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
/// <summary>
/// Object representing a cabinet file on disk; provides access to
/// file-based operations on the cabinet file.
/// </summary>
/// <remarks>
/// Generally, the methods on this class are much easier to use than the
/// stream-based interfaces provided by the <see cref="CabEngine"/> class.
/// </remarks>
[Serializable]
public class CabInfo : ArchiveInfo
{
/// <summary>
/// Creates a new CabinetInfo object representing a cabinet file in a specified path.
/// </summary>
/// <param name="path">The path to the cabinet file. When creating a cabinet file, this file does not
/// necessarily exist yet.</param>
public CabInfo(string path)
: base(path)
{
}
/// <summary>
/// Initializes a new instance of the CabinetInfo class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected CabInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Creates a compression engine that does the low-level work for
/// this object.
/// </summary>
/// <returns>A new <see cref="CabEngine"/> instance.</returns>
/// <remarks>
/// Each instance will be <see cref="CompressionEngine.Dispose()"/>d
/// immediately after use.
/// </remarks>
protected override CompressionEngine CreateCompressionEngine()
{
return new CabEngine();
}
/// <summary>
/// Gets information about the files contained in the archive.
/// </summary>
/// <returns>A list of <see cref="CabFileInfo"/> objects, each
/// containing information about a file in the archive.</returns>
public new IList<CabFileInfo> GetFiles()
{
IList<ArchiveFileInfo> files = base.GetFiles();
List<CabFileInfo> cabFiles = new List<CabFileInfo>(files.Count);
foreach (CabFileInfo cabFile in files) cabFiles.Add(cabFile);
return cabFiles.AsReadOnly();
}
/// <summary>
/// Gets information about the certain files contained in the archive file.
/// </summary>
/// <param name="searchPattern">The search string, such as
/// &quot;*.txt&quot;.</param>
/// <returns>A list of <see cref="CabFileInfo"/> objects, each containing
/// information about a file in the archive.</returns>
public new IList<CabFileInfo> GetFiles(string searchPattern)
{
IList<ArchiveFileInfo> files = base.GetFiles(searchPattern);
List<CabFileInfo> cabFiles = new List<CabFileInfo>(files.Count);
foreach (CabFileInfo cabFile in files) cabFiles.Add(cabFile);
return cabFiles.AsReadOnly();
}
}
}

Просмотреть файл

@ -0,0 +1,667 @@
//---------------------------------------------------------------------
// <copyright file="CabPacker.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.Text;
using System.Security.Permissions;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
internal class CabPacker : CabWorker
{
private const string TempStreamName = "%%TEMP%%";
private NativeMethods.FCI.Handle fciHandle;
// These delegates need to be saved as member variables
// so that they don't get GC'd.
private NativeMethods.FCI.PFNALLOC fciAllocMemHandler;
private NativeMethods.FCI.PFNFREE fciFreeMemHandler;
private NativeMethods.FCI.PFNOPEN fciOpenStreamHandler;
private NativeMethods.FCI.PFNREAD fciReadStreamHandler;
private NativeMethods.FCI.PFNWRITE fciWriteStreamHandler;
private NativeMethods.FCI.PFNCLOSE fciCloseStreamHandler;
private NativeMethods.FCI.PFNSEEK fciSeekStreamHandler;
private NativeMethods.FCI.PFNFILEPLACED fciFilePlacedHandler;
private NativeMethods.FCI.PFNDELETE fciDeleteFileHandler;
private NativeMethods.FCI.PFNGETTEMPFILE fciGetTempFileHandler;
private NativeMethods.FCI.PFNGETNEXTCABINET fciGetNextCabinet;
private NativeMethods.FCI.PFNSTATUS fciCreateStatus;
private NativeMethods.FCI.PFNGETOPENINFO fciGetOpenInfo;
private IPackStreamContext context;
private FileAttributes fileAttributes;
private DateTime fileLastWriteTime;
private int maxCabBytes;
private long totalFolderBytesProcessedInCurrentCab;
private CompressionLevel compressionLevel;
private bool dontUseTempFiles;
private IList<Stream> tempStreams;
public CabPacker(CabEngine cabEngine)
: base(cabEngine)
{
this.fciAllocMemHandler = this.CabAllocMem;
this.fciFreeMemHandler = this.CabFreeMem;
this.fciOpenStreamHandler = this.CabOpenStreamEx;
this.fciReadStreamHandler = this.CabReadStreamEx;
this.fciWriteStreamHandler = this.CabWriteStreamEx;
this.fciCloseStreamHandler = this.CabCloseStreamEx;
this.fciSeekStreamHandler = this.CabSeekStreamEx;
this.fciFilePlacedHandler = this.CabFilePlaced;
this.fciDeleteFileHandler = this.CabDeleteFile;
this.fciGetTempFileHandler = this.CabGetTempFile;
this.fciGetNextCabinet = this.CabGetNextCabinet;
this.fciCreateStatus = this.CabCreateStatus;
this.fciGetOpenInfo = this.CabGetOpenInfo;
this.tempStreams = new List<Stream>();
this.compressionLevel = CompressionLevel.Normal;
}
public bool UseTempFiles
{
get
{
return !this.dontUseTempFiles;
}
set
{
this.dontUseTempFiles = !value;
}
}
public CompressionLevel CompressionLevel
{
get
{
return this.compressionLevel;
}
set
{
this.compressionLevel = value;
}
}
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
private void CreateFci(long maxArchiveSize)
{
NativeMethods.FCI.CCAB ccab = new NativeMethods.FCI.CCAB();
if (maxArchiveSize > 0 && maxArchiveSize < ccab.cb)
{
ccab.cb = Math.Max(
NativeMethods.FCI.MIN_DISK, (int) maxArchiveSize);
}
object maxFolderSizeOption = this.context.GetOption(
"maxFolderSize", null);
if (maxFolderSizeOption != null)
{
long maxFolderSize = Convert.ToInt64(
maxFolderSizeOption, CultureInfo.InvariantCulture);
if (maxFolderSize > 0 && maxFolderSize < ccab.cbFolderThresh)
{
ccab.cbFolderThresh = (int) maxFolderSize;
}
}
this.maxCabBytes = ccab.cb;
ccab.szCab = this.context.GetArchiveName(0);
if (ccab.szCab == null)
{
throw new FileNotFoundException(
"Cabinet name not provided by stream context.");
}
ccab.setID = (short) new Random().Next(
Int16.MinValue, Int16.MaxValue + 1);
this.CabNumbers[ccab.szCab] = 0;
this.currentArchiveName = ccab.szCab;
this.totalArchives = 1;
this.CabStream = null;
this.Erf.Clear();
this.fciHandle = NativeMethods.FCI.Create(
this.ErfHandle.AddrOfPinnedObject(),
this.fciFilePlacedHandler,
this.fciAllocMemHandler,
this.fciFreeMemHandler,
this.fciOpenStreamHandler,
this.fciReadStreamHandler,
this.fciWriteStreamHandler,
this.fciCloseStreamHandler,
this.fciSeekStreamHandler,
this.fciDeleteFileHandler,
this.fciGetTempFileHandler,
ccab,
IntPtr.Zero);
this.CheckError(false);
}
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Pack(
IPackStreamContext streamContext,
IEnumerable<string> files,
long maxArchiveSize)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
if (files == null)
{
throw new ArgumentNullException("files");
}
lock (this)
{
try
{
this.context = streamContext;
this.ResetProgressData();
this.CreateFci(maxArchiveSize);
foreach (string file in files)
{
FileAttributes attributes;
DateTime lastWriteTime;
Stream fileStream = this.context.OpenFileReadStream(
file,
out attributes,
out lastWriteTime);
if (fileStream != null)
{
this.totalFileBytes += fileStream.Length;
this.totalFiles++;
this.context.CloseFileReadStream(file, fileStream);
}
}
long uncompressedBytesInFolder = 0;
this.currentFileNumber = -1;
foreach (string file in files)
{
FileAttributes attributes;
DateTime lastWriteTime;
Stream fileStream = this.context.OpenFileReadStream(
file, out attributes, out lastWriteTime);
if (fileStream == null)
{
continue;
}
if (fileStream.Length >= (long) NativeMethods.FCI.MAX_FOLDER)
{
throw new NotSupportedException(String.Format(
CultureInfo.InvariantCulture,
"File {0} exceeds maximum file size " +
"for cabinet format.",
file));
}
if (uncompressedBytesInFolder > 0)
{
// Automatically create a new folder if this file
// won't fit in the current folder.
bool nextFolder = uncompressedBytesInFolder
+ fileStream.Length >= (long) NativeMethods.FCI.MAX_FOLDER;
// Otherwise ask the client if it wants to
// move to the next folder.
if (!nextFolder)
{
object nextFolderOption = streamContext.GetOption(
"nextFolder",
new object[] { file, this.currentFolderNumber });
nextFolder = Convert.ToBoolean(
nextFolderOption, CultureInfo.InvariantCulture);
}
if (nextFolder)
{
this.FlushFolder();
uncompressedBytesInFolder = 0;
}
}
if (this.currentFolderTotalBytes > 0)
{
this.currentFolderTotalBytes = 0;
this.currentFolderNumber++;
uncompressedBytesInFolder = 0;
}
this.currentFileName = file;
this.currentFileNumber++;
this.currentFileTotalBytes = fileStream.Length;
this.currentFileBytesProcessed = 0;
this.OnProgress(ArchiveProgressType.StartFile);
uncompressedBytesInFolder += fileStream.Length;
this.AddFile(
file,
fileStream,
attributes,
lastWriteTime,
false,
this.CompressionLevel);
}
this.FlushFolder();
this.FlushCabinet();
}
finally
{
if (this.CabStream != null)
{
this.context.CloseArchiveWriteStream(
this.currentArchiveNumber,
this.currentArchiveName,
this.CabStream);
this.CabStream = null;
}
if (this.FileStream != null)
{
this.context.CloseFileReadStream(
this.currentFileName, this.FileStream);
this.FileStream = null;
}
this.context = null;
if (this.fciHandle != null)
{
this.fciHandle.Dispose();
this.fciHandle = null;
}
}
}
}
internal override int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
{
if (this.CabNumbers.ContainsKey(path))
{
Stream stream = this.CabStream;
if (stream == null)
{
short cabNumber = this.CabNumbers[path];
this.currentFolderTotalBytes = 0;
stream = this.context.OpenArchiveWriteStream(cabNumber, path, true, this.CabEngine);
if (stream == null)
{
throw new FileNotFoundException(
String.Format(CultureInfo.InvariantCulture, "Cabinet {0} not provided.", cabNumber));
}
this.currentArchiveName = path;
this.currentArchiveTotalBytes = Math.Min(
this.totalFolderBytesProcessedInCurrentCab, this.maxCabBytes);
this.currentArchiveBytesProcessed = 0;
this.OnProgress(ArchiveProgressType.StartArchive);
this.CabStream = stream;
}
path = CabWorker.CabStreamName;
}
else if (path == CabPacker.TempStreamName)
{
// Opening memory stream for a temp file.
Stream stream = new MemoryStream();
this.tempStreams.Add(stream);
int streamHandle = this.StreamHandles.AllocHandle(stream);
err = 0;
return streamHandle;
}
else if (path != CabWorker.CabStreamName)
{
// Opening a file on disk for a temp file.
path = Path.Combine(Path.GetTempPath(), path);
Stream stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
this.tempStreams.Add(stream);
stream = new DuplicateStream(stream);
int streamHandle = this.StreamHandles.AllocHandle(stream);
err = 0;
return streamHandle;
}
return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv);
}
internal override int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
{
int count = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv);
if (count > 0 && err == 0)
{
Stream stream = this.StreamHandles[streamHandle];
if (DuplicateStream.OriginalStream(stream) ==
DuplicateStream.OriginalStream(this.CabStream))
{
this.currentArchiveBytesProcessed += cb;
if (this.currentArchiveBytesProcessed > this.currentArchiveTotalBytes)
{
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
}
}
}
return count;
}
internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
{
Stream stream = DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]);
if (stream == DuplicateStream.OriginalStream(this.FileStream))
{
this.context.CloseFileReadStream(this.currentFileName, stream);
this.FileStream = null;
long remainder = this.currentFileTotalBytes - this.currentFileBytesProcessed;
this.currentFileBytesProcessed += remainder;
this.fileBytesProcessed += remainder;
this.OnProgress(ArchiveProgressType.FinishFile);
this.currentFileTotalBytes = 0;
this.currentFileBytesProcessed = 0;
this.currentFileName = null;
}
else if (stream == DuplicateStream.OriginalStream(this.CabStream))
{
if (stream.CanWrite)
{
stream.Flush();
}
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
this.OnProgress(ArchiveProgressType.FinishArchive);
this.currentArchiveNumber++;
this.totalArchives++;
this.context.CloseArchiveWriteStream(
this.currentArchiveNumber,
this.currentArchiveName,
stream);
this.currentArchiveName = this.NextCabinetName;
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes = 0;
this.totalFolderBytesProcessedInCurrentCab = 0;
this.CabStream = null;
}
else // Must be a temp stream
{
stream.Close();
this.tempStreams.Remove(stream);
}
return base.CabCloseStreamEx(streamHandle, out err, pv);
}
/// <summary>
/// Disposes of resources allocated by the cabinet engine.
/// </summary>
/// <param name="disposing">If true, the method has been called directly or indirectly by a user's code,
/// so managed and unmanaged resources will be disposed. If false, the method has been called by the
/// runtime from inside the finalizer, and only unmanaged resources will be disposed.</param>
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
if (this.fciHandle != null)
{
this.fciHandle.Dispose();
this.fciHandle = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
private static NativeMethods.FCI.TCOMP GetCompressionType(CompressionLevel compLevel)
{
if (compLevel < CompressionLevel.Min)
{
return NativeMethods.FCI.TCOMP.TYPE_NONE;
}
else
{
if (compLevel > CompressionLevel.Max)
{
compLevel = CompressionLevel.Max;
}
int lzxWindowMax =
((int) NativeMethods.FCI.TCOMP.LZX_WINDOW_HI >> (int) NativeMethods.FCI.TCOMP.SHIFT_LZX_WINDOW) -
((int) NativeMethods.FCI.TCOMP.LZX_WINDOW_LO >> (int) NativeMethods.FCI.TCOMP.SHIFT_LZX_WINDOW);
int lzxWindow = lzxWindowMax *
(compLevel - CompressionLevel.Min) / (CompressionLevel.Max - CompressionLevel.Min);
return (NativeMethods.FCI.TCOMP) ((int) NativeMethods.FCI.TCOMP.TYPE_LZX |
((int) NativeMethods.FCI.TCOMP.LZX_WINDOW_LO +
(lzxWindow << (int) NativeMethods.FCI.TCOMP.SHIFT_LZX_WINDOW)));
}
}
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
private void AddFile(
string name,
Stream stream,
FileAttributes attributes,
DateTime lastWriteTime,
bool execute,
CompressionLevel compLevel)
{
this.FileStream = stream;
this.fileAttributes = attributes &
(FileAttributes.Archive | FileAttributes.Hidden | FileAttributes.ReadOnly | FileAttributes.System);
this.fileLastWriteTime = lastWriteTime;
this.currentFileName = name;
NativeMethods.FCI.TCOMP tcomp = CabPacker.GetCompressionType(compLevel);
IntPtr namePtr = IntPtr.Zero;
try
{
Encoding nameEncoding = Encoding.ASCII;
if (Encoding.UTF8.GetByteCount(name) > name.Length)
{
nameEncoding = Encoding.UTF8;
this.fileAttributes |= FileAttributes.Normal; // _A_NAME_IS_UTF
}
byte[] nameBytes = nameEncoding.GetBytes(name);
namePtr = Marshal.AllocHGlobal(nameBytes.Length + 1);
Marshal.Copy(nameBytes, 0, namePtr, nameBytes.Length);
Marshal.WriteByte(namePtr, nameBytes.Length, 0);
this.Erf.Clear();
NativeMethods.FCI.AddFile(
this.fciHandle,
String.Empty,
namePtr,
execute,
this.fciGetNextCabinet,
this.fciCreateStatus,
this.fciGetOpenInfo,
tcomp);
}
finally
{
if (namePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(namePtr);
}
}
this.CheckError(false);
this.FileStream = null;
this.currentFileName = null;
}
private void FlushFolder()
{
this.Erf.Clear();
NativeMethods.FCI.FlushFolder(this.fciHandle, this.fciGetNextCabinet, this.fciCreateStatus);
this.CheckError(false);
}
private void FlushCabinet()
{
this.Erf.Clear();
NativeMethods.FCI.FlushCabinet(this.fciHandle, false, this.fciGetNextCabinet, this.fciCreateStatus);
this.CheckError(false);
}
private int CabGetOpenInfo(
string path,
out short date,
out short time,
out short attribs,
out int err,
IntPtr pv)
{
CompressionEngine.DateTimeToDosDateAndTime(this.fileLastWriteTime, out date, out time);
attribs = (short) this.fileAttributes;
Stream stream = this.FileStream;
this.FileStream = new DuplicateStream(stream);
int streamHandle = this.StreamHandles.AllocHandle(stream);
err = 0;
return streamHandle;
}
private int CabFilePlaced(
IntPtr pccab,
string filePath,
long fileSize,
int continuation,
IntPtr pv)
{
return 0;
}
private int CabGetNextCabinet(IntPtr pccab, uint prevCabSize, IntPtr pv)
{
NativeMethods.FCI.CCAB nextCcab = new NativeMethods.FCI.CCAB();
Marshal.PtrToStructure(pccab, nextCcab);
nextCcab.szDisk = String.Empty;
nextCcab.szCab = this.context.GetArchiveName(nextCcab.iCab);
this.CabNumbers[nextCcab.szCab] = (short) nextCcab.iCab;
this.NextCabinetName = nextCcab.szCab;
Marshal.StructureToPtr(nextCcab, pccab, false);
return 1;
}
private int CabCreateStatus(NativeMethods.FCI.STATUS typeStatus, uint cb1, uint cb2, IntPtr pv)
{
switch (typeStatus)
{
case NativeMethods.FCI.STATUS.FILE:
if (cb2 > 0 && this.currentFileBytesProcessed < this.currentFileTotalBytes)
{
if (this.currentFileBytesProcessed + cb2 > this.currentFileTotalBytes)
{
cb2 = (uint) this.currentFileTotalBytes - (uint) this.currentFileBytesProcessed;
}
this.currentFileBytesProcessed += cb2;
this.fileBytesProcessed += cb2;
this.OnProgress(ArchiveProgressType.PartialFile);
}
break;
case NativeMethods.FCI.STATUS.FOLDER:
if (cb1 == 0)
{
this.currentFolderTotalBytes = cb2 - this.totalFolderBytesProcessedInCurrentCab;
this.totalFolderBytesProcessedInCurrentCab = cb2;
}
else if (this.currentFolderTotalBytes == 0)
{
this.OnProgress(ArchiveProgressType.PartialArchive);
}
break;
case NativeMethods.FCI.STATUS.CABINET:
break;
}
return 0;
}
private int CabGetTempFile(IntPtr tempNamePtr, int tempNameSize, IntPtr pv)
{
string tempFileName;
if (this.UseTempFiles)
{
tempFileName = Path.GetFileName(Path.GetTempFileName());
}
else
{
tempFileName = CabPacker.TempStreamName;
}
byte[] tempNameBytes = Encoding.ASCII.GetBytes(tempFileName);
if (tempNameBytes.Length >= tempNameSize)
{
return -1;
}
Marshal.Copy(tempNameBytes, 0, tempNamePtr, tempNameBytes.Length);
Marshal.WriteByte(tempNamePtr, tempNameBytes.Length, 0); // null-terminator
return 1;
}
private int CabDeleteFile(string path, out int err, IntPtr pv)
{
try
{
// Deleting a temp file - don't bother if it is only a memory stream.
if (path != CabPacker.TempStreamName)
{
path = Path.Combine(Path.GetTempPath(), path);
File.Delete(path);
}
}
catch (IOException)
{
// Failure to delete a temp file is not fatal.
}
err = 0;
return 1;
}
}
}

Просмотреть файл

@ -0,0 +1,586 @@
//---------------------------------------------------------------------
// <copyright file="CabUnpacker.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.Text;
using System.Security.Permissions;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
internal class CabUnpacker : CabWorker
{
private NativeMethods.FDI.Handle fdiHandle;
// These delegates need to be saved as member variables
// so that they don't get GC'd.
private NativeMethods.FDI.PFNALLOC fdiAllocMemHandler;
private NativeMethods.FDI.PFNFREE fdiFreeMemHandler;
private NativeMethods.FDI.PFNOPEN fdiOpenStreamHandler;
private NativeMethods.FDI.PFNREAD fdiReadStreamHandler;
private NativeMethods.FDI.PFNWRITE fdiWriteStreamHandler;
private NativeMethods.FDI.PFNCLOSE fdiCloseStreamHandler;
private NativeMethods.FDI.PFNSEEK fdiSeekStreamHandler;
private IUnpackStreamContext context;
private List<ArchiveFileInfo> fileList;
private int folderId;
private Predicate<string> filter;
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public CabUnpacker(CabEngine cabEngine)
: base(cabEngine)
{
this.fdiAllocMemHandler = this.CabAllocMem;
this.fdiFreeMemHandler = this.CabFreeMem;
this.fdiOpenStreamHandler = this.CabOpenStream;
this.fdiReadStreamHandler = this.CabReadStream;
this.fdiWriteStreamHandler = this.CabWriteStream;
this.fdiCloseStreamHandler = this.CabCloseStream;
this.fdiSeekStreamHandler = this.CabSeekStream;
this.fdiHandle = NativeMethods.FDI.Create(
this.fdiAllocMemHandler,
this.fdiFreeMemHandler,
this.fdiOpenStreamHandler,
this.fdiReadStreamHandler,
this.fdiWriteStreamHandler,
this.fdiCloseStreamHandler,
this.fdiSeekStreamHandler,
NativeMethods.FDI.CPU_80386,
this.ErfHandle.AddrOfPinnedObject());
if (this.Erf.Error)
{
int error = this.Erf.Oper;
int errorCode = this.Erf.Type;
this.ErfHandle.Free();
throw new CabException(
error,
errorCode,
CabException.GetErrorMessage(error, errorCode, true));
}
}
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public bool IsArchive(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
lock (this)
{
short id;
int folderCount, fileCount;
return this.IsCabinet(stream, out id, out folderCount, out fileCount);
}
}
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public IList<ArchiveFileInfo> GetFileInfo(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
lock (this)
{
this.context = streamContext;
this.filter = fileFilter;
this.NextCabinetName = String.Empty;
this.fileList = new List<ArchiveFileInfo>();
bool tmpSuppress = this.SuppressProgressEvents;
this.SuppressProgressEvents = true;
try
{
for (short cabNumber = 0;
this.NextCabinetName != null;
cabNumber++)
{
this.Erf.Clear();
this.CabNumbers[this.NextCabinetName] = cabNumber;
NativeMethods.FDI.Copy(
this.fdiHandle,
this.NextCabinetName,
String.Empty,
0,
this.CabListNotify,
IntPtr.Zero,
IntPtr.Zero);
this.CheckError(true);
}
List<ArchiveFileInfo> tmpFileList = this.fileList;
this.fileList = null;
return tmpFileList.AsReadOnly();
}
finally
{
this.SuppressProgressEvents = tmpSuppress;
if (this.CabStream != null)
{
this.context.CloseArchiveReadStream(
this.currentArchiveNumber,
this.currentArchiveName,
this.CabStream);
this.CabStream = null;
}
this.context = null;
}
}
}
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Unpack(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
lock (this)
{
IList<ArchiveFileInfo> files =
this.GetFileInfo(streamContext, fileFilter);
this.ResetProgressData();
if (files != null)
{
this.totalFiles = files.Count;
for (int i = 0; i < files.Count; i++)
{
this.totalFileBytes += files[i].Length;
if (files[i].ArchiveNumber >= this.totalArchives)
{
int totalArchives = files[i].ArchiveNumber + 1;
this.totalArchives = (short) totalArchives;
}
}
}
this.context = streamContext;
this.fileList = null;
this.NextCabinetName = String.Empty;
this.folderId = -1;
this.currentFileNumber = -1;
try
{
for (short cabNumber = 0;
this.NextCabinetName != null;
cabNumber++)
{
this.Erf.Clear();
this.CabNumbers[this.NextCabinetName] = cabNumber;
NativeMethods.FDI.Copy(
this.fdiHandle,
this.NextCabinetName,
String.Empty,
0,
this.CabExtractNotify,
IntPtr.Zero,
IntPtr.Zero);
this.CheckError(true);
}
}
finally
{
if (this.CabStream != null)
{
this.context.CloseArchiveReadStream(
this.currentArchiveNumber,
this.currentArchiveName,
this.CabStream);
this.CabStream = null;
}
if (this.FileStream != null)
{
this.context.CloseFileWriteStream(this.currentFileName, this.FileStream, FileAttributes.Normal, DateTime.Now);
this.FileStream = null;
}
this.context = null;
}
}
}
internal override int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
{
if (this.CabNumbers.ContainsKey(path))
{
Stream stream = this.CabStream;
if (stream == null)
{
short cabNumber = this.CabNumbers[path];
stream = this.context.OpenArchiveReadStream(cabNumber, path, this.CabEngine);
if (stream == null)
{
throw new FileNotFoundException(String.Format(CultureInfo.InvariantCulture, "Cabinet {0} not provided.", cabNumber));
}
this.currentArchiveName = path;
this.currentArchiveNumber = cabNumber;
if (this.totalArchives <= this.currentArchiveNumber)
{
int totalArchives = this.currentArchiveNumber + 1;
this.totalArchives = (short) totalArchives;
}
this.currentArchiveTotalBytes = stream.Length;
this.currentArchiveBytesProcessed = 0;
if (this.folderId != -3) // -3 is a special folderId that requires re-opening the same cab
{
this.OnProgress(ArchiveProgressType.StartArchive);
}
this.CabStream = stream;
}
path = CabWorker.CabStreamName;
}
return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv);
}
internal override int CabReadStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
{
int count = base.CabReadStreamEx(streamHandle, memory, cb, out err, pv);
if (err == 0 && this.CabStream != null)
{
if (this.fileList == null)
{
Stream stream = this.StreamHandles[streamHandle];
if (DuplicateStream.OriginalStream(stream) ==
DuplicateStream.OriginalStream(this.CabStream))
{
this.currentArchiveBytesProcessed += cb;
if (this.currentArchiveBytesProcessed > this.currentArchiveTotalBytes)
{
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
}
}
}
}
return count;
}
internal override int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
{
int count = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv);
if (count > 0 && err == 0)
{
this.currentFileBytesProcessed += cb;
this.fileBytesProcessed += cb;
this.OnProgress(ArchiveProgressType.PartialFile);
}
return count;
}
internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
{
Stream stream = DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]);
if (stream == DuplicateStream.OriginalStream(this.CabStream))
{
if (this.folderId != -3) // -3 is a special folderId that requires re-opening the same cab
{
this.OnProgress(ArchiveProgressType.FinishArchive);
}
this.context.CloseArchiveReadStream(this.currentArchiveNumber, this.currentArchiveName, stream);
this.currentArchiveName = this.NextCabinetName;
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes = 0;
this.CabStream = null;
}
return base.CabCloseStreamEx(streamHandle, out err, pv);
}
/// <summary>
/// Disposes of resources allocated by the cabinet engine.
/// </summary>
/// <param name="disposing">If true, the method has been called directly or indirectly by a user's code,
/// so managed and unmanaged resources will be disposed. If false, the method has been called by the
/// runtime from inside the finalizer, and only unmanaged resources will be disposed.</param>
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
if (this.fdiHandle != null)
{
this.fdiHandle.Dispose();
this.fdiHandle = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
private static string GetFileName(NativeMethods.FDI.NOTIFICATION notification)
{
bool utf8Name = (notification.attribs & (ushort) FileAttributes.Normal) != 0; // _A_NAME_IS_UTF
// Non-utf8 names should be completely ASCII. But for compatibility with
// legacy tools, interpret them using the current (Default) ANSI codepage.
Encoding nameEncoding = utf8Name ? Encoding.UTF8 : Encoding.Default;
// Find how many bytes are in the string.
// Unfortunately there is no faster way.
int nameBytesCount = 0;
while (Marshal.ReadByte(notification.psz1, nameBytesCount) != 0)
{
nameBytesCount++;
}
byte[] nameBytes = new byte[nameBytesCount];
Marshal.Copy(notification.psz1, nameBytes, 0, nameBytesCount);
string name = nameEncoding.GetString(nameBytes);
if (Path.IsPathRooted(name))
{
name = name.Replace("" + Path.VolumeSeparatorChar, "");
}
return name;
}
private bool IsCabinet(Stream cabStream, out short id, out int cabFolderCount, out int fileCount)
{
int streamHandle = this.StreamHandles.AllocHandle(cabStream);
try
{
this.Erf.Clear();
NativeMethods.FDI.CABINFO fdici;
bool isCabinet = 0 != NativeMethods.FDI.IsCabinet(this.fdiHandle, streamHandle, out fdici);
if (this.Erf.Error)
{
if (((NativeMethods.FDI.ERROR) this.Erf.Oper) == NativeMethods.FDI.ERROR.UNKNOWN_CABINET_VERSION)
{
isCabinet = false;
}
else
{
throw new CabException(
this.Erf.Oper,
this.Erf.Type,
CabException.GetErrorMessage(this.Erf.Oper, this.Erf.Type, true));
}
}
id = fdici.setID;
cabFolderCount = (int) fdici.cFolders;
fileCount = (int) fdici.cFiles;
return isCabinet;
}
finally
{
this.StreamHandles.FreeHandle(streamHandle);
}
}
private int CabListNotify(NativeMethods.FDI.NOTIFICATIONTYPE notificationType, NativeMethods.FDI.NOTIFICATION notification)
{
switch (notificationType)
{
case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO:
{
string nextCab = Marshal.PtrToStringAnsi(notification.psz1);
this.NextCabinetName = (nextCab.Length != 0 ? nextCab : null);
return 0; // Continue
}
case NativeMethods.FDI.NOTIFICATIONTYPE.PARTIAL_FILE:
{
// This notification can occur when examining the contents of a non-first cab file.
return 0; // Continue
}
case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE:
{
//bool execute = (notification.attribs & (ushort) FileAttributes.Device) != 0; // _A_EXEC
string name = CabUnpacker.GetFileName(notification);
if (this.filter == null || this.filter(name))
{
if (this.fileList != null)
{
FileAttributes attributes = (FileAttributes) notification.attribs &
(FileAttributes.Archive | FileAttributes.Hidden | FileAttributes.ReadOnly | FileAttributes.System);
if (attributes == (FileAttributes) 0)
{
attributes = FileAttributes.Normal;
}
DateTime lastWriteTime;
CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out lastWriteTime);
long length = notification.cb;
CabFileInfo fileInfo = new CabFileInfo(
name,
notification.iFolder,
notification.iCabinet,
attributes,
lastWriteTime,
length);
this.fileList.Add(fileInfo);
this.currentFileNumber = this.fileList.Count - 1;
this.fileBytesProcessed += notification.cb;
}
}
this.totalFiles++;
this.totalFileBytes += notification.cb;
return 0; // Continue
}
}
return 0;
}
private int CabExtractNotify(NativeMethods.FDI.NOTIFICATIONTYPE notificationType, NativeMethods.FDI.NOTIFICATION notification)
{
switch (notificationType)
{
case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO:
{
if (this.NextCabinetName != null && this.NextCabinetName.StartsWith("?", StringComparison.Ordinal))
{
// We are just continuing the copy of a file that spanned cabinets.
// The next cabinet name needs to be preserved.
this.NextCabinetName = this.NextCabinetName.Substring(1);
}
else
{
string nextCab = Marshal.PtrToStringAnsi(notification.psz1);
this.NextCabinetName = (nextCab.Length != 0 ? nextCab : null);
}
return 0; // Continue
}
case NativeMethods.FDI.NOTIFICATIONTYPE.NEXT_CABINET:
{
string nextCab = Marshal.PtrToStringAnsi(notification.psz1);
this.CabNumbers[nextCab] = (short) notification.iCabinet;
this.NextCabinetName = "?" + this.NextCabinetName;
return 0; // Continue
}
case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE:
{
return this.CabExtractCopyFile(notification);
}
case NativeMethods.FDI.NOTIFICATIONTYPE.CLOSE_FILE_INFO:
{
return this.CabExtractCloseFile(notification);
}
}
return 0;
}
private int CabExtractCopyFile(NativeMethods.FDI.NOTIFICATION notification)
{
if (notification.iFolder != this.folderId)
{
if (notification.iFolder != -3) // -3 is a special folderId used when continuing a folder from a previous cab
{
if (this.folderId != -1) // -1 means we just started the extraction sequence
{
this.currentFolderNumber++;
}
}
this.folderId = notification.iFolder;
}
//bool execute = (notification.attribs & (ushort) FileAttributes.Device) != 0; // _A_EXEC
string name = CabUnpacker.GetFileName(notification);
if (this.filter == null || this.filter(name))
{
this.currentFileNumber++;
this.currentFileName = name;
this.currentFileBytesProcessed = 0;
this.currentFileTotalBytes = notification.cb;
this.OnProgress(ArchiveProgressType.StartFile);
DateTime lastWriteTime;
CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out lastWriteTime);
Stream stream = this.context.OpenFileWriteStream(name, notification.cb, lastWriteTime);
if (stream != null)
{
this.FileStream = stream;
int streamHandle = this.StreamHandles.AllocHandle(stream);
return streamHandle;
}
else
{
this.fileBytesProcessed += notification.cb;
this.OnProgress(ArchiveProgressType.FinishFile);
this.currentFileName = null;
}
}
return 0; // Continue
}
private int CabExtractCloseFile(NativeMethods.FDI.NOTIFICATION notification)
{
Stream stream = this.StreamHandles[notification.hf];
this.StreamHandles.FreeHandle(notification.hf);
//bool execute = (notification.attribs & (ushort) FileAttributes.Device) != 0; // _A_EXEC
string name = CabUnpacker.GetFileName(notification);
FileAttributes attributes = (FileAttributes) notification.attribs &
(FileAttributes.Archive | FileAttributes.Hidden | FileAttributes.ReadOnly | FileAttributes.System);
if (attributes == (FileAttributes) 0)
{
attributes = FileAttributes.Normal;
}
DateTime lastWriteTime;
CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out lastWriteTime);
stream.Flush();
this.context.CloseFileWriteStream(name, stream, attributes, lastWriteTime);
this.FileStream = null;
long remainder = this.currentFileTotalBytes - this.currentFileBytesProcessed;
this.currentFileBytesProcessed += remainder;
this.fileBytesProcessed += remainder;
this.OnProgress(ArchiveProgressType.FinishFile);
this.currentFileName = null;
return 1; // Continue
}
}
}

Просмотреть файл

@ -0,0 +1,347 @@
//---------------------------------------------------------------------
// <copyright file="CabWorker.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Text;
using System.Security;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
internal abstract class CabWorker : IDisposable
{
internal const string CabStreamName = "%%CAB%%";
private CabEngine cabEngine;
private HandleManager<Stream> streamHandles;
private Stream cabStream;
private Stream fileStream;
private NativeMethods.ERF erf;
private GCHandle erfHandle;
private IDictionary<string, short> cabNumbers;
private string nextCabinetName;
private bool suppressProgressEvents;
private byte[] buf;
// Progress data
protected string currentFileName;
protected int currentFileNumber;
protected int totalFiles;
protected long currentFileBytesProcessed;
protected long currentFileTotalBytes;
protected short currentFolderNumber;
protected long currentFolderTotalBytes;
protected string currentArchiveName;
protected short currentArchiveNumber;
protected short totalArchives;
protected long currentArchiveBytesProcessed;
protected long currentArchiveTotalBytes;
protected long fileBytesProcessed;
protected long totalFileBytes;
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
protected CabWorker(CabEngine cabEngine)
{
this.cabEngine = cabEngine;
this.streamHandles = new HandleManager<Stream>();
this.erf = new NativeMethods.ERF();
this.erfHandle = GCHandle.Alloc(this.erf, GCHandleType.Pinned);
this.cabNumbers = new Dictionary<string, short>(1);
// 32K seems to be the size of the largest chunks processed by cabinet.dll.
// But just in case, this buffer will auto-enlarge.
this.buf = new byte[32768];
}
~CabWorker()
{
this.Dispose(false);
}
public CabEngine CabEngine
{
get
{
return this.cabEngine;
}
}
internal NativeMethods.ERF Erf
{
get
{
return this.erf;
}
}
internal GCHandle ErfHandle
{
get
{
return this.erfHandle;
}
}
internal HandleManager<Stream> StreamHandles
{
get
{
return this.streamHandles;
}
}
internal bool SuppressProgressEvents
{
get
{
return this.suppressProgressEvents;
}
set
{
this.suppressProgressEvents = value;
}
}
internal IDictionary<string, short> CabNumbers
{
get
{
return this.cabNumbers;
}
}
internal string NextCabinetName
{
get
{
return this.nextCabinetName;
}
set
{
this.nextCabinetName = value;
}
}
internal Stream CabStream
{
get
{
return this.cabStream;
}
set
{
this.cabStream = value;
}
}
internal Stream FileStream
{
get
{
return this.fileStream;
}
set
{
this.fileStream = value;
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void ResetProgressData()
{
this.currentFileName = null;
this.currentFileNumber = 0;
this.totalFiles = 0;
this.currentFileBytesProcessed = 0;
this.currentFileTotalBytes = 0;
this.currentFolderNumber = 0;
this.currentFolderTotalBytes = 0;
this.currentArchiveName = null;
this.currentArchiveNumber = 0;
this.totalArchives = 0;
this.currentArchiveBytesProcessed = 0;
this.currentArchiveTotalBytes = 0;
this.fileBytesProcessed = 0;
this.totalFileBytes = 0;
}
protected void OnProgress(ArchiveProgressType progressType)
{
if (!this.suppressProgressEvents)
{
ArchiveProgressEventArgs e = new ArchiveProgressEventArgs(
progressType,
this.currentFileName,
this.currentFileNumber >= 0 ? this.currentFileNumber : 0,
this.totalFiles,
this.currentFileBytesProcessed,
this.currentFileTotalBytes,
this.currentArchiveName,
this.currentArchiveNumber,
this.totalArchives,
this.currentArchiveBytesProcessed,
this.currentArchiveTotalBytes,
this.fileBytesProcessed,
this.totalFileBytes);
this.CabEngine.ReportProgress(e);
}
}
internal IntPtr CabAllocMem(int byteCount)
{
IntPtr memPointer = Marshal.AllocHGlobal((IntPtr) byteCount);
return memPointer;
}
internal void CabFreeMem(IntPtr memPointer)
{
Marshal.FreeHGlobal(memPointer);
}
internal int CabOpenStream(string path, int openFlags, int shareMode)
{
int err; return this.CabOpenStreamEx(path, openFlags, shareMode, out err, IntPtr.Zero);
}
internal virtual int CabOpenStreamEx(string path, int openFlags, int shareMode, out int err, IntPtr pv)
{
path = path.Trim();
Stream stream = this.cabStream;
this.cabStream = new DuplicateStream(stream);
int streamHandle = this.streamHandles.AllocHandle(stream);
err = 0;
return streamHandle;
}
internal int CabReadStream(int streamHandle, IntPtr memory, int cb)
{
int err; return this.CabReadStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
}
internal virtual int CabReadStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
{
Stream stream = this.streamHandles[streamHandle];
int count = (int) cb;
if (count > this.buf.Length)
{
this.buf = new byte[count];
}
count = stream.Read(this.buf, 0, count);
Marshal.Copy(this.buf, 0, memory, count);
err = 0;
return count;
}
internal int CabWriteStream(int streamHandle, IntPtr memory, int cb)
{
int err; return this.CabWriteStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero);
}
internal virtual int CabWriteStreamEx(int streamHandle, IntPtr memory, int cb, out int err, IntPtr pv)
{
Stream stream = this.streamHandles[streamHandle];
int count = (int) cb;
if (count > this.buf.Length)
{
this.buf = new byte[count];
}
Marshal.Copy(memory, this.buf, 0, count);
stream.Write(this.buf, 0, count);
err = 0;
return cb;
}
internal int CabCloseStream(int streamHandle)
{
int err; return this.CabCloseStreamEx(streamHandle, out err, IntPtr.Zero);
}
internal virtual int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv)
{
this.streamHandles.FreeHandle(streamHandle);
err = 0;
return 0;
}
internal int CabSeekStream(int streamHandle, int offset, int seekOrigin)
{
int err; return this.CabSeekStreamEx(streamHandle, offset, seekOrigin, out err, IntPtr.Zero);
}
internal virtual int CabSeekStreamEx(int streamHandle, int offset, int seekOrigin, out int err, IntPtr pv)
{
Stream stream = this.streamHandles[streamHandle];
offset = (int) stream.Seek(offset, (SeekOrigin) seekOrigin);
err = 0;
return offset;
}
/// <summary>
/// Disposes of resources allocated by the cabinet engine.
/// </summary>
/// <param name="disposing">If true, the method has been called directly or indirectly by a user's code,
/// so managed and unmanaged resources will be disposed. If false, the method has been called by the
/// runtime from inside the finalizer, and only unmanaged resources will be disposed.</param>
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (this.cabStream != null)
{
this.cabStream.Close();
this.cabStream = null;
}
if (this.fileStream != null)
{
this.fileStream.Close();
this.fileStream = null;
}
}
if (this.erfHandle.IsAllocated)
{
this.erfHandle.Free();
}
}
protected void CheckError(bool extracting)
{
if (this.Erf.Error)
{
throw new CabException(
this.Erf.Oper,
this.Erf.Type,
CabException.GetErrorMessage(this.Erf.Oper, this.Erf.Type, extracting));
}
}
}
}

Просмотреть файл

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="Compression.Cab.csproj" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{15895FD1-DD68-407B-8717-08F6DD14F02C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Deployment.Compression.Cab</RootNamespace>
<AssemblyName>Microsoft.Deployment.Compression.Cab</AssemblyName>
<CreateDocumentationFile>true</CreateDocumentationFile>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FxCopEnabled>false</FxCopEnabled>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="CabPacker.cs" />
<Compile Include="CabEngine.cs" />
<Compile Include="CabWorker.cs" />
<Compile Include="CabException.cs" />
<Compile Include="CabUnpacker.cs" />
<Compile Include="CabFileInfo.cs" />
<Compile Include="CabInfo.cs" />
<Compile Include="HandleManager.cs" />
<Compile Include="NativeMethods.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Errors.txt" />
<EmbeddedResource Include="Errors.resources" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<ProjectReference Include="..\Compression\Compression.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

Двоичные данные
src/DTF/Libraries/Compression.Cab/Errors.resources Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,35 @@
;
; Cabinet Error Messages
;
; Generic error message.
1=Error code: {1}
;
; Cabinet creation messages - offset by 1000
;
1000=Unknown error creating cabinet.
1001=Failure opening file to be stored in cabinet.
1002=Failure reading file to be stored in cabinet.
1003=Could not allocate enough memory to create cabinet.
1004=Could not create a temporary file.
1005=Unknown compression type.
1006=Could not create cabinet file.
1007=Client requested abort.
1008=Failure compressing data.
;
; Cabinet extraction messages - offset by 2000
;
2000=Unknown error extracting cabinet.
2001=Cabinet not found.
2002=Cabinet file does not have the correct format.
2003=Cabinet file has an unknown version number.
2004=Cabinet file is corrupt.
2005=Could not allocate enough memory to extract cabinet.
2006=Unknown compression type in a cabinet folder.
2007=Failure decompressing data from a cabinet file.
2008=Failure writing to target file.
2009=Cabinets in a set do not have the same RESERVE sizes.
2010=Cabinet returned on NEXT_CABINET is incorrect.
2011=Client requested abort.

Просмотреть файл

@ -0,0 +1,86 @@
//---------------------------------------------------------------------
// <copyright file="HandleManager.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.Collections.Generic;
/// <summary>
/// Generic class for managing allocations of integer handles
/// for objects of a certain type.
/// </summary>
/// <typeparam name="T">The type of objects the handles refer to.</typeparam>
internal sealed class HandleManager<T> where T : class
{
/// <summary>
/// Auto-resizing list of objects for which handles have been allocated.
/// Each handle is just an index into this list. When a handle is freed,
/// the list item at that index is set to null.
/// </summary>
private List<T> handles;
/// <summary>
/// Creates a new HandleManager instance.
/// </summary>
public HandleManager()
{
this.handles = new List<T>();
}
/// <summary>
/// Gets the object of a handle, or null if the handle is invalid.
/// </summary>
/// <param name="handle">The integer handle previously allocated
/// for the desired object.</param>
/// <returns>The object for which the handle was allocated.</returns>
public T this[int handle]
{
get
{
if (handle > 0 && handle <= this.handles.Count)
{
return this.handles[handle - 1];
}
else
{
return null;
}
}
}
/// <summary>
/// Allocates a new handle for an object.
/// </summary>
/// <param name="obj">Object that the handle will refer to.</param>
/// <returns>New handle that can be later used to retrieve the object.</returns>
public int AllocHandle(T obj)
{
this.handles.Add(obj);
int handle = this.handles.Count;
return handle;
}
/// <summary>
/// Frees a handle that was previously allocated. Afterward the handle
/// will be invalid and the object it referred to can no longer retrieved.
/// </summary>
/// <param name="handle">Handle to be freed.</param>
public void FreeHandle(int handle)
{
if (handle > 0 && handle <= this.handles.Count)
{
this.handles[handle - 1] = null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,419 @@
//---------------------------------------------------------------------
// <copyright file="NativeMethods.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Cab
{
using System;
using System.Text;
using System.Security;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Native DllImport methods and related structures and constants used for
/// cabinet creation and extraction via cabinet.dll.
/// </summary>
internal static class NativeMethods
{
/// <summary>
/// A direct import of constants, enums, structures, delegates, and functions from fci.h.
/// Refer to comments in fci.h for documentation.
/// </summary>
internal static class FCI
{
internal const int MIN_DISK = 32768;
internal const int MAX_DISK = Int32.MaxValue;
internal const int MAX_FOLDER = 0x7FFF8000;
internal const int MAX_FILENAME = 256;
internal const int MAX_CABINET_NAME = 256;
internal const int MAX_CAB_PATH = 256;
internal const int MAX_DISK_NAME = 256;
internal const int CPU_80386 = 1;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate IntPtr PFNALLOC(int cb);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void PFNFREE(IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNOPEN(string path, int oflag, int pmode, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNREAD(int fileHandle, IntPtr memory, int cb, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNWRITE(int fileHandle, IntPtr memory, int cb, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNCLOSE(int fileHandle, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNSEEK(int fileHandle, int dist, int seekType, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNDELETE(string path, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNGETNEXTCABINET(IntPtr pccab, uint cbPrevCab, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNFILEPLACED(IntPtr pccab, string path, long fileSize, int continuation, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNGETOPENINFO(string path, out short date, out short time, out short pattribs, out int err, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNSTATUS(STATUS typeStatus, uint cb1, uint cb2, IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNGETTEMPFILE(IntPtr tempNamePtr, int tempNameSize, IntPtr pv);
/// <summary>
/// Error codes that can be returned by FCI.
/// </summary>
internal enum ERROR : int
{
NONE,
OPEN_SRC,
READ_SRC,
ALLOC_FAIL,
TEMP_FILE,
BAD_COMPR_TYPE,
CAB_FILE,
USER_ABORT,
MCI_FAIL,
}
/// <summary>
/// FCI compression algorithm types and parameters.
/// </summary>
internal enum TCOMP : ushort
{
MASK_TYPE = 0x000F,
TYPE_NONE = 0x0000,
TYPE_MSZIP = 0x0001,
TYPE_QUANTUM = 0x0002,
TYPE_LZX = 0x0003,
BAD = 0x000F,
MASK_LZX_WINDOW = 0x1F00,
LZX_WINDOW_LO = 0x0F00,
LZX_WINDOW_HI = 0x1500,
SHIFT_LZX_WINDOW = 0x0008,
MASK_QUANTUM_LEVEL = 0x00F0,
QUANTUM_LEVEL_LO = 0x0010,
QUANTUM_LEVEL_HI = 0x0070,
SHIFT_QUANTUM_LEVEL = 0x0004,
MASK_QUANTUM_MEM = 0x1F00,
QUANTUM_MEM_LO = 0x0A00,
QUANTUM_MEM_HI = 0x1500,
SHIFT_QUANTUM_MEM = 0x0008,
MASK_RESERVED = 0xE000,
}
/// <summary>
/// Reason for FCI status callback.
/// </summary>
internal enum STATUS : uint
{
FILE = 0,
FOLDER = 1,
CABINET = 2,
}
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments")]
[DllImport("cabinet.dll", EntryPoint = "FCICreate", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern Handle Create(IntPtr perf, PFNFILEPLACED pfnfcifp, PFNALLOC pfna, PFNFREE pfnf, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, PFNDELETE pfndelete, PFNGETTEMPFILE pfnfcigtf, [MarshalAs(UnmanagedType.LPStruct)] CCAB pccab, IntPtr pv);
[DllImport("cabinet.dll", EntryPoint = "FCIAddFile", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int AddFile(Handle hfci, string pszSourceFile, IntPtr pszFileName, [MarshalAs(UnmanagedType.Bool)] bool fExecute, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis, PFNGETOPENINFO pfnfcigoi, TCOMP typeCompress);
[DllImport("cabinet.dll", EntryPoint = "FCIFlushCabinet", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int FlushCabinet(Handle hfci, [MarshalAs(UnmanagedType.Bool)] bool fGetNextCab, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis);
[DllImport("cabinet.dll", EntryPoint = "FCIFlushFolder", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int FlushFolder(Handle hfci, PFNGETNEXTCABINET pfnfcignc, PFNSTATUS pfnfcis);
[SuppressUnmanagedCodeSecurity]
[DllImport("cabinet.dll", EntryPoint = "FCIDestroy", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool Destroy(IntPtr hfci);
/// <summary>
/// Cabinet information structure used for FCI initialization and GetNextCabinet callback.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class CCAB
{
internal int cb = MAX_DISK;
internal int cbFolderThresh = MAX_FOLDER;
internal int cbReserveCFHeader;
internal int cbReserveCFFolder;
internal int cbReserveCFData;
internal int iCab;
internal int iDisk;
internal int fFailOnIncompressible;
internal short setID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_DISK_NAME )] internal string szDisk = String.Empty;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_CABINET_NAME)] internal string szCab = String.Empty;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_CAB_PATH )] internal string szCabPath = String.Empty;
}
/// <summary>
/// Ensures that the FCI handle is safely released.
/// </summary>
internal class Handle : SafeHandle
{
/// <summary>
/// Creates a new unintialized handle. The handle will be initialized
/// when it is marshalled back from native code.
/// </summary>
internal Handle()
: base(IntPtr.Zero, true)
{
}
/// <summary>
/// Checks if the handle is invalid. An FCI handle is invalid when it is zero.
/// </summary>
public override bool IsInvalid
{
get
{
return this.handle == IntPtr.Zero;
}
}
/// <summary>
/// Releases the handle by calling FDIDestroy().
/// </summary>
/// <returns>True if the release succeeded.</returns>
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
protected override bool ReleaseHandle()
{
return FCI.Destroy(this.handle);
}
}
}
/// <summary>
/// A direct import of constants, enums, structures, delegates, and functions from fdi.h.
/// Refer to comments in fdi.h for documentation.
/// </summary>
internal static class FDI
{
internal const int MAX_DISK = Int32.MaxValue;
internal const int MAX_FILENAME = 256;
internal const int MAX_CABINET_NAME = 256;
internal const int MAX_CAB_PATH = 256;
internal const int MAX_DISK_NAME = 256;
internal const int CPU_80386 = 1;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate IntPtr PFNALLOC(int cb);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void PFNFREE(IntPtr pv);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNOPEN(string path, int oflag, int pmode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNREAD(int hf, IntPtr pv, int cb);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNWRITE(int hf, IntPtr pv, int cb);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNCLOSE(int hf);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNSEEK(int hf, int dist, int seektype);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int PFNNOTIFY(NOTIFICATIONTYPE fdint, NOTIFICATION fdin);
/// <summary>
/// Error codes that can be returned by FDI.
/// </summary>
internal enum ERROR : int
{
NONE,
CABINET_NOT_FOUND,
NOT_A_CABINET,
UNKNOWN_CABINET_VERSION,
CORRUPT_CABINET,
ALLOC_FAIL,
BAD_COMPR_TYPE,
MDI_FAIL,
TARGET_FILE,
RESERVE_MISMATCH,
WRONG_CABINET,
USER_ABORT,
}
/// <summary>
/// Type of notification message for the FDI Notify callback.
/// </summary>
internal enum NOTIFICATIONTYPE : int
{
CABINET_INFO,
PARTIAL_FILE,
COPY_FILE,
CLOSE_FILE_INFO,
NEXT_CABINET,
ENUMERATE,
}
[DllImport("cabinet.dll", EntryPoint = "FDICreate", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern Handle Create([MarshalAs(UnmanagedType.FunctionPtr)] PFNALLOC pfnalloc, [MarshalAs(UnmanagedType.FunctionPtr)] PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, IntPtr perf);
[DllImport("cabinet.dll", EntryPoint = "FDICopy", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int Copy(Handle hfdi, string pszCabinet, string pszCabPath, int flags, PFNNOTIFY pfnfdin, IntPtr pfnfdid, IntPtr pvUser);
[SuppressUnmanagedCodeSecurity]
[DllImport("cabinet.dll", EntryPoint = "FDIDestroy", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool Destroy(IntPtr hfdi);
[DllImport("cabinet.dll", EntryPoint = "FDIIsCabinet", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Justification="FDI file handles definitely remain 4 bytes on 64bit platforms.")]
internal static extern int IsCabinet(Handle hfdi, int hf, out CABINFO pfdici);
/// <summary>
/// Cabinet information structure filled in by FDI IsCabinet.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct CABINFO
{
internal int cbCabinet;
internal short cFolders;
internal short cFiles;
internal short setID;
internal short iCabinet;
internal int fReserve;
internal int hasprev;
internal int hasnext;
}
/// <summary>
/// Cabinet notification details passed to the FDI Notify callback.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class NOTIFICATION
{
internal int cb;
internal IntPtr psz1;
internal IntPtr psz2;
internal IntPtr psz3;
internal IntPtr pv;
internal IntPtr hf_ptr;
internal short date;
internal short time;
internal short attribs;
internal short setID;
internal short iCabinet;
internal short iFolder;
internal int fdie;
// Unlike all the other file handles in FCI/FDI, this one is
// actually pointer-sized. Use a property to pretend it isn't.
internal int hf
{
get { return (int) this.hf_ptr; }
}
}
/// <summary>
/// Ensures that the FDI handle is safely released.
/// </summary>
internal class Handle : SafeHandle
{
/// <summary>
/// Creates a new unintialized handle. The handle will be initialized
/// when it is marshalled back from native code.
/// </summary>
internal Handle()
: base(IntPtr.Zero, true)
{
}
/// <summary>
/// Checks if the handle is invalid. An FDI handle is invalid when it is zero.
/// </summary>
public override bool IsInvalid
{
get
{
return this.handle == IntPtr.Zero;
}
}
/// <summary>
/// Releases the handle by calling FDIDestroy().
/// </summary>
/// <returns>True if the release succeeded.</returns>
protected override bool ReleaseHandle()
{
return FDI.Destroy(this.handle);
}
}
}
/// <summary>
/// Error info structure for FCI and FDI.
/// </summary>
/// <remarks>Before being passed to FCI or FDI, this structure is
/// pinned in memory via a GCHandle. The pinning is necessary
/// to be able to read the results, since the ERF structure doesn't
/// get marshalled back out after an error.</remarks>
[StructLayout(LayoutKind.Sequential)]
internal class ERF
{
private int erfOper;
private int erfType;
private int fError;
/// <summary>
/// Gets or sets the cabinet error code.
/// </summary>
internal int Oper
{
get
{
return this.erfOper;
}
set
{
this.erfOper = value;
}
}
/// <summary>
/// Gets or sets the Win32 error code.
/// </summary>
internal int Type
{
get
{
return this.erfType;
}
set
{
this.erfType = value;
}
}
/// <summary>
/// GCHandle doesn't like the bool type, so use an int underneath.
/// </summary>
internal bool Error
{
get
{
return this.fError != 0;
}
set
{
this.fError = value ? 1 : 0;
}
}
/// <summary>
/// Clears the error information.
/// </summary>
internal void Clear()
{
this.Oper = 0;
this.Type = 0;
this.Error = false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
[assembly: AssemblyDescription("Managed libraries for zip archive packing and unpacking")]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
// SECURITY: The UnmanagedCode assertions in the zip classes are safe, because
// only some very limited date-time unmanaged APIs are called.
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion = true, UnmanagedCode = true)]
// SECURITY: Review carefully!
// This assembly is designed so that partially trusted callers should be able to
// do zip compression and extraction in a file path where they have limited
// file I/O permission. Or they can even do in-memory compression and extraction
// with absolutely no file I/O permission.
[assembly: AllowPartiallyTrustedCallers]
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Deployment.Compression.Zip")]

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="Compression.Zip.csproj" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{261F2857-B521-42A4-A3E0-B5165F225E50}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Deployment.Compression.Zip</RootNamespace>
<AssemblyName>Microsoft.Deployment.Compression.Zip</AssemblyName>
<CreateDocumentationFile>true</CreateDocumentationFile>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="ConcatStream.cs" />
<Compile Include="CrcStream.cs" />
<Compile Include="ZipCompressionMethod.cs" />
<Compile Include="ZipException.cs" />
<Compile Include="ZipEngine.cs" />
<Compile Include="ZipFileInfo.cs" />
<Compile Include="ZipFormat.cs" />
<Compile Include="ZipInfo.cs" />
<Compile Include="ZipPacker.cs" />
<Compile Include="ZipUnpacker.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<ProjectReference Include="..\Compression\Compression.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,167 @@
//---------------------------------------------------------------------
// <copyright file="ConcatStream.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
/// <summary>
/// Used to trick a DeflateStream into reading from or writing to
/// a series of (chunked) streams instead of a single steream.
/// </summary>
internal class ConcatStream : Stream
{
private Stream source;
private long position;
private long length;
private Action<ConcatStream> nextStreamHandler;
public ConcatStream(Action<ConcatStream> nextStreamHandler)
{
if (nextStreamHandler == null)
{
throw new ArgumentNullException("nextStreamHandler");
}
this.nextStreamHandler = nextStreamHandler;
this.length = Int64.MaxValue;
}
public Stream Source
{
get { return this.source; }
set { this.source = value; }
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override long Length
{
get
{
return this.length;
}
}
public override long Position
{
get { return this.position; }
set { throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (this.source == null)
{
this.nextStreamHandler(this);
}
count = (int) Math.Min(count, this.length - this.position);
int bytesRemaining = count;
while (bytesRemaining > 0)
{
if (this.source == null)
{
throw new InvalidOperationException();
}
int partialCount = (int) Math.Min(bytesRemaining,
this.source.Length - this.source.Position);
if (partialCount == 0)
{
this.nextStreamHandler(this);
continue;
}
partialCount = this.source.Read(
buffer, offset + count - bytesRemaining, partialCount);
bytesRemaining -= partialCount;
this.position += partialCount;
}
return count;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (this.source == null)
{
this.nextStreamHandler(this);
}
int bytesRemaining = count;
while (bytesRemaining > 0)
{
if (this.source == null)
{
throw new InvalidOperationException();
}
int partialCount = (int) Math.Min(bytesRemaining,
Math.Max(0, this.length - this.source.Position));
if (partialCount == 0)
{
this.nextStreamHandler(this);
continue;
}
this.source.Write(
buffer, offset + count - bytesRemaining, partialCount);
bytesRemaining -= partialCount;
this.position += partialCount;
}
}
public override void Flush()
{
if (this.source != null)
{
this.source.Flush();
}
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
this.length = value;
}
public override void Close()
{
if (this.source != null)
{
this.source.Close();
}
}
}
}

Просмотреть файл

@ -0,0 +1,261 @@
//---------------------------------------------------------------------
// <copyright file="CrcStream.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Wraps a source stream and calcaluates a CRC over all bytes that are read or written.
/// </summary>
/// <remarks>
/// The CRC algorithm matches that used in the standard ZIP file format.
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Crc")]
public class CrcStream : Stream
{
private Stream source;
private uint crc;
/// <summary>
/// Creates a new CrcStream instance from a source stream.
/// </summary>
/// <param name="source">Underlying stream where bytes will be read from or written to.</param>
public CrcStream(Stream source)
{
this.source = source;
}
/// <summary>
/// Gets the current CRC over all bytes that have been read or written
/// since this instance was created.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Crc")]
[CLSCompliant(false)]
public uint Crc
{
get
{
return this.crc;
}
}
/// <summary>
/// Gets the underlying stream that this stream reads from or writes to.
/// </summary>
public Stream Source
{
get
{
return this.source;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports reading.
/// </summary>
/// <value>true if the stream supports reading; otherwise, false.</value>
public override bool CanRead
{
get
{
return this.source.CanRead;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports writing.
/// </summary>
/// <value>true if the stream supports writing; otherwise, false.</value>
public override bool CanWrite
{
get
{
return this.source.CanWrite;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports seeking.
/// </summary>
/// <value>true if the stream supports seeking; otherwise, false.</value>
public override bool CanSeek
{
get
{
return this.source.CanSeek;
}
}
/// <summary>
/// Gets the length of the source stream.
/// </summary>
public override long Length
{
get
{
return this.source.Length;
}
}
/// <summary>
/// Gets or sets the position of the source stream.
/// </summary>
public override long Position
{
get
{
return this.source.Position;
}
set
{
this.source.Position = value;
}
}
/// <summary>
/// Sets the position within the source stream.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type SeekOrigin indicating
/// the reference point used to obtain the new position.</param>
/// <returns>The new position within the source stream.</returns>
/// <remarks>
/// Note the CRC is only calculated over bytes that are actually read or
/// written, so any bytes skipped by seeking will not contribute to the CRC.
/// </remarks>
public override long Seek(long offset, SeekOrigin origin)
{
return this.source.Seek(offset, origin);
}
/// <summary>
/// Sets the length of the source stream.
/// </summary>
/// <param name="value">The desired length of the
/// stream in bytes.</param>
public override void SetLength(long value)
{
this.source.SetLength(value);
}
/// <summary>
/// Reads a sequence of bytes from the source stream and advances
/// the position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer
/// contains the specified byte array with the values between offset and
/// (offset + count - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin
/// storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>The total number of bytes read into the buffer. This can be less
/// than the number of bytes requested if that many bytes are not currently available,
/// or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
count = this.source.Read(buffer, offset, count);
this.UpdateCrc(buffer, offset, count);
return count;
}
/// <summary>
/// Writes a sequence of bytes to the source stream and advances the
/// current position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count
/// bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which
/// to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the
/// current stream.</param>
public override void Write(byte[] buffer, int offset, int count)
{
this.source.Write(buffer, offset, count);
this.UpdateCrc(buffer, offset, count);
}
/// <summary>
/// Flushes the source stream.
/// </summary>
public override void Flush()
{
this.source.Flush();
}
/// <summary>
/// Closes the underlying stream.
/// </summary>
public override void Close()
{
this.source.Close();
base.Close();
}
/// <summary>
/// Updates the CRC with a range of bytes that were read or written.
/// </summary>
private void UpdateCrc(byte[] buffer, int offset, int count)
{
this.crc = ~this.crc;
for( ; count > 0; count--, offset++)
{
this.crc = (this.crc >> 8) ^
CrcStream.crcTable[(this.crc & 0xFF) ^ buffer[offset]];
}
this.crc = ~this.crc;
}
private static uint[] crcTable = MakeCrcTable();
/// <summary>
/// Computes a table that speeds up calculation of the CRC.
/// </summary>
private static uint[] MakeCrcTable()
{
const uint poly = 0x04C11DB7u;
uint[] crcTable = new uint[256];
for(uint n = 0; n < 256; n++)
{
uint c = CrcStream.Reflect(n, 8);
c = c << 24;
for(uint k = 0; k < 8; k++)
{
c = (c << 1) ^ ((c & 0x80000000u) != 0 ? poly : 0);
}
crcTable[n] = CrcStream.Reflect(c, 32);
}
return crcTable;
}
/// <summary>
/// Reflects the ordering of certain number of bits. For exmample when reflecting
/// one byte, bit one is swapped with bit eight, bit two with bit seven, etc.
/// </summary>
private static uint Reflect(uint value, int bits)
{
for (int i = 0; i < bits / 2; i++)
{
uint leftBit = 1u << (bits - 1 - i);
uint rightBit = 1u << i;
if (((value & leftBit) != 0) != ((value & rightBit) != 0))
{
value ^= leftBit | rightBit;
}
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
//---------------------------------------------------------------------
// <copyright file="ZipCompressionMethod.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Identifies the compression method or &quot;algorithm&quot;
/// used for a single file within a zip archive.
/// </summary>
/// <remarks>
/// Proprietary zip implementations may define additional compression
/// methods outside of those included here.
/// </remarks>
public enum ZipCompressionMethod
{
/// <summary>
/// The file is stored (no compression)
/// </summary>
Store = 0,
/// <summary>
/// The file is Shrunk
/// </summary>
Shrink = 1,
/// <summary>
/// The file is Reduced with compression factor 1
/// </summary>
Reduce1 = 2,
/// <summary>
/// The file is Reduced with compression factor 2
/// </summary>
Reduce2 = 3,
/// <summary>
/// The file is Reduced with compression factor 3
/// </summary>
Reduce3 = 4,
/// <summary>
/// The file is Reduced with compression factor 4
/// </summary>
Reduce4 = 5,
/// <summary>
/// The file is Imploded
/// </summary>
Implode = 6,
/// <summary>
/// The file is Deflated;
/// the most common and widely-compatible form of zip compression.
/// </summary>
Deflate = 8,
/// <summary>
/// The file is Deflated using the enhanced Deflate64 method.
/// </summary>
Deflate64 = 9,
/// <summary>
/// The file is compressed using the BZIP2 algorithm.
/// </summary>
BZip2 = 12,
/// <summary>
/// The file is compressed using the LZMA algorithm.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Lzma")]
Lzma = 14,
/// <summary>
/// The file is compressed using the PPMd algorithm.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ppmd")]
Ppmd = 98
}
}

Просмотреть файл

@ -0,0 +1,488 @@
//---------------------------------------------------------------------
// <copyright file="ZipEngine.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.IO.Compression;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Engine capable of packing and unpacking archives in the zip format.
/// </summary>
public partial class ZipEngine : CompressionEngine
{
private static Dictionary<ZipCompressionMethod, Converter<Stream, Stream>>
compressionStreamCreators;
private static Dictionary<ZipCompressionMethod, Converter<Stream, Stream>>
decompressionStreamCreators;
private static void InitCompressionStreamCreators()
{
if (ZipEngine.compressionStreamCreators == null)
{
ZipEngine.compressionStreamCreators = new
Dictionary<ZipCompressionMethod, Converter<Stream, Stream>>();
ZipEngine.decompressionStreamCreators = new
Dictionary<ZipCompressionMethod, Converter<Stream, Stream>>();
ZipEngine.RegisterCompressionStreamCreator(
ZipCompressionMethod.Store,
CompressionMode.Compress,
delegate(Stream stream) {
return stream;
});
ZipEngine.RegisterCompressionStreamCreator(
ZipCompressionMethod.Deflate,
CompressionMode.Compress,
delegate(Stream stream) {
return new DeflateStream(stream, CompressionMode.Compress, true);
});
ZipEngine.RegisterCompressionStreamCreator(
ZipCompressionMethod.Store,
CompressionMode.Decompress,
delegate(Stream stream) {
return stream;
});
ZipEngine.RegisterCompressionStreamCreator(
ZipCompressionMethod.Deflate,
CompressionMode.Decompress,
delegate(Stream stream) {
return new DeflateStream(stream, CompressionMode.Decompress, true);
});
}
}
/// <summary>
/// Registers a delegate that can create a warpper stream for
/// compressing or uncompressing the data of a source stream.
/// </summary>
/// <param name="compressionMethod">Compression method being registered.</param>
/// <param name="compressionMode">Indicates registration for ether
/// compress or decompress mode.</param>
/// <param name="creator">Delegate being registered.</param>
/// <remarks>
/// For compression, the delegate accepts a stream that writes to the archive
/// and returns a wrapper stream that compresses bytes as they are written.
/// For decompression, the delegate accepts a stream that reads from the archive
/// and returns a wrapper stream that decompresses bytes as they are read.
/// This wrapper stream model follows the design used by
/// System.IO.Compression.DeflateStream, and indeed that class is used
/// to implement the Deflate compression method by default.
/// <para>To unregister a delegate, call this method again and pass
/// null for the delegate parameter.</para>
/// </remarks>
/// <example>
/// When the ZipEngine class is initialized, the Deflate compression method
/// is automatically registered like this:
/// <code>
/// ZipEngine.RegisterCompressionStreamCreator(
/// ZipCompressionMethod.Deflate,
/// CompressionMode.Compress,
/// delegate(Stream stream) {
/// return new DeflateStream(stream, CompressionMode.Compress, true);
/// });
/// ZipEngine.RegisterCompressionStreamCreator(
/// ZipCompressionMethod.Deflate,
/// CompressionMode.Decompress,
/// delegate(Stream stream) {
/// return new DeflateStream(stream, CompressionMode.Decompress, true);
/// });
/// </code></example>
public static void RegisterCompressionStreamCreator(
ZipCompressionMethod compressionMethod,
CompressionMode compressionMode,
Converter<Stream, Stream> creator)
{
ZipEngine.InitCompressionStreamCreators();
if (compressionMode == CompressionMode.Compress)
{
ZipEngine.compressionStreamCreators[compressionMethod] = creator;
}
else
{
ZipEngine.decompressionStreamCreators[compressionMethod] = creator;
}
}
// Progress data
private string currentFileName;
private int currentFileNumber;
private int totalFiles;
private long currentFileBytesProcessed;
private long currentFileTotalBytes;
private string mainArchiveName;
private string currentArchiveName;
private short currentArchiveNumber;
private short totalArchives;
private long currentArchiveBytesProcessed;
private long currentArchiveTotalBytes;
private long fileBytesProcessed;
private long totalFileBytes;
private string comment;
/// <summary>
/// Creates a new instance of the zip engine.
/// </summary>
public ZipEngine()
: base()
{
ZipEngine.InitCompressionStreamCreators();
}
/// <summary>
/// Gets the comment from the last-examined archive,
/// or sets the comment to be added to any created archives.
/// </summary>
public string ArchiveComment
{
get
{
return this.comment;
}
set
{
this.comment = value;
}
}
/// <summary>
/// Checks whether a Stream begins with a header that indicates
/// it is a valid archive file.
/// </summary>
/// <param name="stream">Stream for reading the archive file.</param>
/// <returns>True if the stream is a valid zip archive
/// (with no offset); false otherwise.</returns>
public override bool IsArchive(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (stream.Length - stream.Position < 4)
{
return false;
}
BinaryReader reader = new BinaryReader(stream);
uint sig = reader.ReadUInt32();
switch (sig)
{
case ZipFileHeader.LFHSIG:
case ZipEndOfCentralDirectory.EOCDSIG:
case ZipEndOfCentralDirectory.EOCD64SIG:
case ZipFileHeader.SPANSIG:
case ZipFileHeader.SPANSIG2:
return true;
default:
return false;
}
}
/// <summary>
/// Gets the offset of an archive that is positioned 0 or more bytes
/// from the start of the Stream.
/// </summary>
/// <param name="stream">A stream for reading the archive.</param>
/// <returns>The offset in bytes of the archive,
/// or -1 if no archive is found in the Stream.</returns>
/// <remarks>The archive must begin on a 4-byte boundary.</remarks>
public override long FindArchiveOffset(Stream stream)
{
long offset = base.FindArchiveOffset(stream);
if (offset > 0)
{
// Some self-extract packages include the exe stub in file offset calculations.
// Check the first header directory offset to decide whether the entire
// archive needs to be offset or not.
ZipEndOfCentralDirectory eocd = this.GetEOCD(null, stream);
if (eocd != null && eocd.totalEntries > 0)
{
stream.Seek(eocd.dirOffset, SeekOrigin.Begin);
ZipFileHeader header = new ZipFileHeader();
if (header.Read(stream, true) && header.localHeaderOffset < stream.Length)
{
stream.Seek(header.localHeaderOffset, SeekOrigin.Begin);
if (header.Read(stream, false))
{
return 0;
}
}
}
}
return offset;
}
/// <summary>
/// Gets information about files in a zip archive or archive chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="fileFilter">A predicate that can determine
/// which files to process, optional.</param>
/// <returns>Information about files in the archive stream.</returns>
/// <exception cref="ArchiveException">The archive provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public override IList<ArchiveFileInfo> GetFileInfo(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
lock (this)
{
IList<ZipFileHeader> headers = this.GetCentralDirectory(streamContext);
if (headers == null)
{
throw new ZipException("Zip central directory not found.");
}
List<ArchiveFileInfo> files = new List<ArchiveFileInfo>(headers.Count);
foreach (ZipFileHeader header in headers)
{
if (!header.IsDirectory &&
(fileFilter == null || fileFilter(header.fileName)))
{
files.Add(header.ToZipFileInfo());
}
}
return files.AsReadOnly();
}
}
/// <summary>
/// Reads all the file headers from the central directory in the main archive.
/// </summary>
private IList<ZipFileHeader> GetCentralDirectory(IUnpackStreamContext streamContext)
{
Stream archiveStream = null;
this.currentArchiveNumber = 0;
try
{
List<ZipFileHeader> headers = new List<ZipFileHeader>();
archiveStream = this.OpenArchive(streamContext, 0);
ZipEndOfCentralDirectory eocd = this.GetEOCD(streamContext, archiveStream);
if (eocd == null)
{
return null;
}
else if (eocd.totalEntries == 0)
{
return headers;
}
headers.Capacity = (int) eocd.totalEntries;
if (eocd.dirOffset > archiveStream.Length - ZipFileHeader.CFH_FIXEDSIZE)
{
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber, String.Empty, archiveStream);
archiveStream = null;
}
else
{
archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin);
uint sig = new BinaryReader(archiveStream).ReadUInt32();
if (sig != ZipFileHeader.CFHSIG)
{
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber, String.Empty, archiveStream);
archiveStream = null;
}
}
if (archiveStream == null)
{
this.currentArchiveNumber = (short) (eocd.dirStartDiskNumber + 1);
archiveStream = streamContext.OpenArchiveReadStream(
this.currentArchiveNumber, String.Empty, this);
if (archiveStream == null)
{
return null;
}
}
archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin);
while (headers.Count < eocd.totalEntries)
{
ZipFileHeader header = new ZipFileHeader();
if (!header.Read(archiveStream, true))
{
throw new ZipException(
"Missing or invalid central directory file header");
}
headers.Add(header);
if (headers.Count < eocd.totalEntries &&
archiveStream.Position == archiveStream.Length)
{
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber, String.Empty, archiveStream);
this.currentArchiveNumber++;
archiveStream = streamContext.OpenArchiveReadStream(
this.currentArchiveNumber, String.Empty, this);
if (archiveStream == null)
{
this.currentArchiveNumber = 0;
archiveStream = streamContext.OpenArchiveReadStream(
this.currentArchiveNumber, String.Empty, this);
}
}
}
return headers;
}
finally
{
if (archiveStream != null)
{
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber, String.Empty, archiveStream);
}
}
}
/// <summary>
/// Locates and reads the end of central directory record near the
/// end of the archive.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "streamContext")]
private ZipEndOfCentralDirectory GetEOCD(
IUnpackStreamContext streamContext, Stream archiveStream)
{
BinaryReader reader = new BinaryReader(archiveStream);
long offset = archiveStream.Length
- ZipEndOfCentralDirectory.EOCD_RECORD_FIXEDSIZE;
while (offset >= 0)
{
archiveStream.Seek(offset, SeekOrigin.Begin);
uint sig = reader.ReadUInt32();
if (sig == ZipEndOfCentralDirectory.EOCDSIG)
{
break;
}
offset--;
}
if (offset < 0)
{
return null;
}
ZipEndOfCentralDirectory eocd = new ZipEndOfCentralDirectory();
archiveStream.Seek(offset, SeekOrigin.Begin);
if (!eocd.Read(archiveStream))
{
throw new ZipException("Invalid end of central directory record");
}
if (eocd.dirOffset == (long) UInt32.MaxValue)
{
string saveComment = eocd.comment;
archiveStream.Seek(
offset - Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE,
SeekOrigin.Begin);
Zip64EndOfCentralDirectoryLocator eocdl =
new Zip64EndOfCentralDirectoryLocator();
if (!eocdl.Read(archiveStream))
{
throw new ZipException("Missing or invalid end of " +
"central directory record locator");
}
if (eocdl.dirStartDiskNumber == eocdl.totalDisks - 1)
{
// ZIP64 eocd is entirely in current stream.
archiveStream.Seek(eocdl.dirOffset, SeekOrigin.Begin);
if (!eocd.Read(archiveStream))
{
throw new ZipException("Missing or invalid ZIP64 end of " +
"central directory record");
}
}
else if (streamContext == null)
{
return null;
}
else
{
// TODO: handle EOCD64 spanning archives!
throw new NotImplementedException("Zip implementation does not " +
"handle end of central directory record that spans archives.");
}
eocd.comment = saveComment;
}
return eocd;
}
private void ResetProgressData()
{
this.currentFileName = null;
this.currentFileNumber = 0;
this.totalFiles = 0;
this.currentFileBytesProcessed = 0;
this.currentFileTotalBytes = 0;
this.currentArchiveName = null;
this.currentArchiveNumber = 0;
this.totalArchives = 0;
this.currentArchiveBytesProcessed = 0;
this.currentArchiveTotalBytes = 0;
this.fileBytesProcessed = 0;
this.totalFileBytes = 0;
}
private void OnProgress(ArchiveProgressType progressType)
{
ArchiveProgressEventArgs e = new ArchiveProgressEventArgs(
progressType,
this.currentFileName,
this.currentFileNumber >= 0 ? this.currentFileNumber : 0,
this.totalFiles,
this.currentFileBytesProcessed,
this.currentFileTotalBytes,
this.currentArchiveName,
this.currentArchiveNumber,
this.totalArchives,
this.currentArchiveBytesProcessed,
this.currentArchiveTotalBytes,
this.fileBytesProcessed,
this.totalFileBytes);
this.OnProgress(e);
}
}
}

Просмотреть файл

@ -0,0 +1,72 @@
//---------------------------------------------------------------------
// <copyright file="ZipException.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.Resources;
using System.Globalization;
using System.Security.Permissions;
using System.Runtime.Serialization;
/// <summary>
/// Exception class for zip operations.
/// </summary>
[Serializable]
public class ZipException : ArchiveException
{
/// <summary>
/// Creates a new ZipException with a specified error message and a reference to the
/// inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If the
/// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception
/// is raised in a catch block that handles the inner exception.</param>
public ZipException(string message, Exception innerException)
: base(message, innerException) { }
/// <summary>
/// Creates a new ZipException with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ZipException(string message)
: this(message, null) { }
/// <summary>
/// Creates a new ZipException.
/// </summary>
public ZipException()
: this(null, null) { }
/// <summary>
/// Initializes a new instance of the ZipException class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected ZipException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
/// <summary>
/// Sets the SerializationInfo with information about the exception.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
}
}

Просмотреть файл

@ -0,0 +1,116 @@
//---------------------------------------------------------------------
// <copyright file="ZipFileInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Permissions;
/// <summary>
/// Object representing a compressed file within a zip package; provides operations for getting
/// the file properties and extracting the file.
/// </summary>
[Serializable]
public class ZipFileInfo : ArchiveFileInfo
{
private long compressedLength;
private ZipCompressionMethod compressionMethod;
/// <summary>
/// Creates a new ZipFileInfo object representing a file within a zip in a specified path.
/// </summary>
/// <param name="zipInfo">An object representing the zip archive containing the file.</param>
/// <param name="filePath">The path to the file within the zip archive. Usually, this is a simple file
/// name, but if the zip archive contains a directory structure this may include the directory.</param>
public ZipFileInfo(ZipInfo zipInfo, string filePath)
: base(zipInfo, filePath)
{
if (zipInfo == null)
{
throw new ArgumentNullException("zipInfo");
}
}
/// <summary>
/// Creates a new ZipFileInfo object with all parameters specified,
/// used internally when reading the metadata out of a zip archive.
/// </summary>
/// <param name="filePath">The internal path and name of the file in the zip archive.</param>
/// <param name="zipNumber">The zip archive number where the file starts.</param>
/// <param name="attributes">The stored attributes of the file.</param>
/// <param name="lastWriteTime">The stored last write time of the file.</param>
/// <param name="length">The uncompressed size of the file.</param>
/// <param name="compressedLength">The compressed size of the file.</param>
/// <param name="compressionMethod">Compression algorithm used for this file.</param>
internal ZipFileInfo(
string filePath,
int zipNumber,
FileAttributes attributes,
DateTime lastWriteTime,
long length,
long compressedLength,
ZipCompressionMethod compressionMethod)
: base(filePath, zipNumber, attributes, lastWriteTime, length)
{
this.compressedLength = compressedLength;
this.compressionMethod = compressionMethod;
}
/// <summary>
/// Initializes a new instance of the ZipFileInfo class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected ZipFileInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.compressedLength = info.GetInt64("compressedLength");
}
/// <summary>
/// Gets the compressed size of the file in bytes.
/// </summary>
public long CompressedLength
{
get
{
return this.compressedLength;
}
}
/// <summary>
/// Gets the method used to compress this file.
/// </summary>
public ZipCompressionMethod CompressionMethod
{
get
{
return this.compressionMethod;
}
}
/// <summary>
/// Sets the SerializationInfo with information about the archive.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data.</param>
/// <param name="context">The StreamingContext that contains contextual information
/// about the source or destination.</param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("compressedLength", this.compressedLength);
}
}
}

Просмотреть файл

@ -0,0 +1,707 @@
//---------------------------------------------------------------------
// <copyright file="ZipFormat.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
[Flags]
internal enum ZipFileFlags : ushort
{
None = 0x0000,
Encrypt = 0x0001,
CompressOption1 = 0x0002,
CompressOption2 = 0x0004,
DataDescriptor = 0x0008,
StrongEncrypt = 0x0040,
UTF8 = 0x0800
}
internal enum ZipExtraFileFieldType : ushort
{
ZIP64 = 0x0001,
NTFS_TIMES = 0x000A,
NTFS_ACLS = 0x4453,
EXTIME = 0x5455
}
internal class ZipFileHeader
{
public const uint LFHSIG = 0x04034B50;
public const uint CFHSIG = 0x02014B50;
public const uint SPANSIG = 0x08074b50;
public const uint SPANSIG2 = 0x30304b50;
public const uint LFH_FIXEDSIZE = 30;
public const uint CFH_FIXEDSIZE = 46;
public ushort versionMadeBy;
public ushort versionNeeded;
public ZipFileFlags flags;
public ZipCompressionMethod compressionMethod;
public short lastModTime;
public short lastModDate;
public uint crc32;
public uint compressedSize;
public uint uncompressedSize;
public ushort diskStart;
public ushort internalFileAttrs;
public uint externalFileAttrs;
public uint localHeaderOffset;
public string fileName;
public ZipExtraFileField[] extraFields;
public string fileComment;
public bool zip64;
public ZipFileHeader()
{
this.versionMadeBy = 20;
this.versionNeeded = 20;
}
public ZipFileHeader(ZipFileInfo fileInfo, bool zip64)
: this()
{
this.flags = ZipFileFlags.None;
this.compressionMethod = fileInfo.CompressionMethod;
this.fileName = Path.Combine(fileInfo.Path, fileInfo.Name);
CompressionEngine.DateTimeToDosDateAndTime(
fileInfo.LastWriteTime, out this.lastModDate, out this.lastModTime);
this.zip64 = zip64;
if (this.zip64)
{
this.compressedSize = UInt32.MaxValue;
this.uncompressedSize = UInt32.MaxValue;
this.diskStart = UInt16.MaxValue;
this.versionMadeBy = 45;
this.versionNeeded = 45;
ZipExtraFileField field = new ZipExtraFileField();
field.fieldType = ZipExtraFileFieldType.ZIP64;
field.SetZip64Data(
fileInfo.CompressedLength,
fileInfo.Length,
0,
fileInfo.ArchiveNumber);
this.extraFields = new ZipExtraFileField[] { field };
}
else
{
this.compressedSize = (uint) fileInfo.CompressedLength;
this.uncompressedSize = (uint) fileInfo.Length;
this.diskStart = (ushort) fileInfo.ArchiveNumber;
}
}
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "compressedSize")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "uncompressedSize")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "crc32")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "localHeaderOffset")]
public void Update(
long compressedSize,
long uncompressedSize,
uint crc32,
long localHeaderOffset,
int archiveNumber)
{
this.crc32 = crc32;
if (this.zip64)
{
this.compressedSize = UInt32.MaxValue;
this.uncompressedSize = UInt32.MaxValue;
this.localHeaderOffset = UInt32.MaxValue;
this.diskStart = UInt16.MaxValue;
if (this.extraFields != null)
{
foreach (ZipExtraFileField field in this.extraFields)
{
if (field.fieldType == ZipExtraFileFieldType.ZIP64)
{
field.SetZip64Data(
compressedSize,
uncompressedSize,
localHeaderOffset,
archiveNumber);
}
}
}
}
else
{
this.compressedSize = (uint) compressedSize;
this.uncompressedSize = (uint) uncompressedSize;
this.localHeaderOffset = (uint) localHeaderOffset;
this.diskStart = (ushort) archiveNumber;
}
}
public bool Read(Stream stream, bool central)
{
long startPos = stream.Position;
if (stream.Length - startPos <
(central ? CFH_FIXEDSIZE : LFH_FIXEDSIZE))
{
return false;
}
BinaryReader reader = new BinaryReader(stream);
uint sig = reader.ReadUInt32();
if (sig == SPANSIG || sig == SPANSIG2)
{
// Spanned zip files may optionally begin with a special marker.
// Just ignore it and move on.
sig = reader.ReadUInt32();
}
if (sig != (central ? CFHSIG : LFHSIG))
{
return false;
}
this.versionMadeBy = (central ? reader.ReadUInt16() : (ushort) 0);
this.versionNeeded = reader.ReadUInt16();
this.flags = (ZipFileFlags) reader.ReadUInt16();
this.compressionMethod = (ZipCompressionMethod) reader.ReadUInt16();
this.lastModTime = reader.ReadInt16();
this.lastModDate = reader.ReadInt16();
this.crc32 = reader.ReadUInt32();
this.compressedSize = reader.ReadUInt32();
this.uncompressedSize = reader.ReadUInt32();
this.zip64 = this.uncompressedSize == UInt32.MaxValue;
int fileNameLength = reader.ReadUInt16();
int extraFieldLength = reader.ReadUInt16();
int fileCommentLength;
if (central)
{
fileCommentLength = reader.ReadUInt16();
this.diskStart = reader.ReadUInt16();
this.internalFileAttrs = reader.ReadUInt16();
this.externalFileAttrs = reader.ReadUInt32();
this.localHeaderOffset = reader.ReadUInt32();
}
else
{
fileCommentLength = 0;
this.diskStart = 0;
this.internalFileAttrs = 0;
this.externalFileAttrs = 0;
this.localHeaderOffset = 0;
}
if (stream.Length - stream.Position <
fileNameLength + extraFieldLength + fileCommentLength)
{
return false;
}
Encoding headerEncoding = ((this.flags | ZipFileFlags.UTF8) != 0 ?
Encoding.UTF8 : Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage));
byte[] fileNameBytes = reader.ReadBytes(fileNameLength);
this.fileName = headerEncoding.GetString(fileNameBytes).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
List<ZipExtraFileField> fields = new List<ZipExtraFileField>();
while (extraFieldLength > 0)
{
ZipExtraFileField field = new ZipExtraFileField();
if (!field.Read(stream, ref extraFieldLength))
{
return false;
}
fields.Add(field);
if (field.fieldType == ZipExtraFileFieldType.ZIP64)
{
this.zip64 = true;
}
}
this.extraFields = fields.ToArray();
byte[] fileCommentBytes = reader.ReadBytes(fileCommentLength);
this.fileComment = headerEncoding.GetString(fileCommentBytes);
return true;
}
public void Write(Stream stream, bool central)
{
byte[] fileNameBytes = (this.fileName != null
? Encoding.UTF8.GetBytes(this.fileName) : new byte[0]);
byte[] fileCommentBytes = (this.fileComment != null
? Encoding.UTF8.GetBytes(this.fileComment) : new byte[0]);
bool useUtf8 =
(this.fileName != null && fileNameBytes.Length > this.fileName.Length) ||
(this.fileComment != null && fileCommentBytes.Length > this.fileComment.Length);
if (useUtf8)
{
this.flags |= ZipFileFlags.UTF8;
}
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(central ? CFHSIG : LFHSIG);
if (central)
{
writer.Write(this.versionMadeBy);
}
writer.Write(this.versionNeeded);
writer.Write((ushort) this.flags);
writer.Write((ushort) this.compressionMethod);
writer.Write(this.lastModTime);
writer.Write(this.lastModDate);
writer.Write(this.crc32);
writer.Write(this.compressedSize);
writer.Write(this.uncompressedSize);
ushort extraFieldLength = 0;
if (this.extraFields != null)
{
foreach (ZipExtraFileField field in this.extraFields)
{
if (field.data != null)
{
extraFieldLength += (ushort) (4 + field.data.Length);
}
}
}
writer.Write((ushort) fileNameBytes.Length);
writer.Write(extraFieldLength);
if (central)
{
writer.Write((ushort) fileCommentBytes.Length);
writer.Write(this.diskStart);
writer.Write(this.internalFileAttrs);
writer.Write(this.externalFileAttrs);
writer.Write(this.localHeaderOffset);
}
writer.Write(fileNameBytes);
if (this.extraFields != null)
{
foreach (ZipExtraFileField field in this.extraFields)
{
if (field.data != null)
{
field.Write(stream);
}
}
}
if (central)
{
writer.Write(fileCommentBytes);
}
}
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "compressedSize")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "uncompressedSize")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "crc32")]
[SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "localHeaderOffset")]
public void GetZip64Fields(
out long compressedSize,
out long uncompressedSize,
out long localHeaderOffset,
out int archiveNumber,
out uint crc)
{
compressedSize = this.compressedSize;
uncompressedSize = this.uncompressedSize;
localHeaderOffset = this.localHeaderOffset;
archiveNumber = this.diskStart;
crc = this.crc32;
foreach (ZipExtraFileField field in this.extraFields)
{
if (field.fieldType == ZipExtraFileFieldType.ZIP64)
{
field.GetZip64Data(
out compressedSize,
out uncompressedSize,
out localHeaderOffset,
out archiveNumber);
}
}
}
public ZipFileInfo ToZipFileInfo()
{
string name = this.fileName;
long compressedSizeL;
long uncompressedSizeL;
long localHeaderOffsetL;
int archiveNumberL;
uint crc;
this.GetZip64Fields(
out compressedSizeL,
out uncompressedSizeL,
out localHeaderOffsetL,
out archiveNumberL,
out crc);
DateTime dateTime;
CompressionEngine.DosDateAndTimeToDateTime(
this.lastModDate,
this.lastModTime,
out dateTime);
FileAttributes attrs = FileAttributes.Normal;
// TODO: look for attrs or times in extra fields
return new ZipFileInfo(name, archiveNumberL, attrs, dateTime,
uncompressedSizeL, compressedSizeL, this.compressionMethod);
}
public bool IsDirectory
{
get
{
return this.fileName != null &&
(this.fileName.EndsWith("/", StringComparison.Ordinal) ||
this.fileName.EndsWith("\\", StringComparison.Ordinal));
}
}
public int GetSize(bool central)
{
int size = 30;
int fileNameSize = (this.fileName != null
? Encoding.UTF8.GetByteCount(this.fileName) : 0);
size += fileNameSize;
if (this.extraFields != null)
{
foreach (ZipExtraFileField field in this.extraFields)
{
if (field.data != null)
{
size += 4 + field.data.Length;
}
}
}
if (central)
{
size += 16;
int fileCommentSize = (this.fileComment != null
? Encoding.UTF8.GetByteCount(this.fileComment) : 0);
size += fileCommentSize;
}
return size;
}
}
internal class ZipExtraFileField
{
public ZipExtraFileFieldType fieldType;
public byte[] data;
public bool Read(Stream stream, ref int bytesRemaining)
{
if (bytesRemaining < 4)
{
return false;
}
BinaryReader reader = new BinaryReader(stream);
this.fieldType = (ZipExtraFileFieldType) reader.ReadUInt16();
ushort dataSize = reader.ReadUInt16();
bytesRemaining -= 4;
if (bytesRemaining < dataSize)
{
return false;
}
this.data = reader.ReadBytes(dataSize);
bytesRemaining -= dataSize;
return true;
}
public void Write(Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write((ushort) this.fieldType);
byte[] dataBytes = (this.data != null ? this.data : new byte[0]);
writer.Write((ushort) dataBytes.Length);
writer.Write(dataBytes);
}
public bool GetZip64Data(
out long compressedSize,
out long uncompressedSize,
out long localHeaderOffset,
out int diskStart)
{
uncompressedSize = 0;
compressedSize = 0;
localHeaderOffset = 0;
diskStart = 0;
if (this.fieldType != ZipExtraFileFieldType.ZIP64 ||
this.data == null || this.data.Length != 28)
{
return false;
}
using (MemoryStream dataStream = new MemoryStream(this.data))
{
BinaryReader reader = new BinaryReader(dataStream);
uncompressedSize = reader.ReadInt64();
compressedSize = reader.ReadInt64();
localHeaderOffset = reader.ReadInt64();
diskStart = reader.ReadInt32();
}
return true;
}
public bool SetZip64Data(
long compressedSize,
long uncompressedSize,
long localHeaderOffset,
int diskStart)
{
if (this.fieldType != ZipExtraFileFieldType.ZIP64)
{
return false;
}
using (MemoryStream dataStream = new MemoryStream())
{
BinaryWriter writer = new BinaryWriter(dataStream);
writer.Write(uncompressedSize);
writer.Write(compressedSize);
writer.Write(localHeaderOffset);
writer.Write(diskStart);
this.data = dataStream.ToArray();
}
return true;
}
}
internal class ZipEndOfCentralDirectory
{
public const uint EOCDSIG = 0x06054B50;
public const uint EOCD64SIG = 0x06064B50;
public const uint EOCD_RECORD_FIXEDSIZE = 22;
public const uint EOCD64_RECORD_FIXEDSIZE = 56;
public ushort versionMadeBy;
public ushort versionNeeded;
public uint diskNumber;
public uint dirStartDiskNumber;
public long entriesOnDisk;
public long totalEntries;
public long dirSize;
public long dirOffset;
public string comment;
public bool zip64;
public ZipEndOfCentralDirectory()
{
this.versionMadeBy = 20;
this.versionNeeded = 20;
}
public bool Read(Stream stream)
{
long startPos = stream.Position;
if (stream.Length - startPos < EOCD_RECORD_FIXEDSIZE)
{
return false;
}
BinaryReader reader = new BinaryReader(stream);
uint sig = reader.ReadUInt32();
this.zip64 = false;
if (sig != EOCDSIG)
{
if (sig == EOCD64SIG)
{
this.zip64 = true;
}
else
{
return false;
}
}
if (this.zip64)
{
if (stream.Length - startPos < EOCD64_RECORD_FIXEDSIZE)
{
return false;
}
long recordSize = reader.ReadInt64();
this.versionMadeBy = reader.ReadUInt16();
this.versionNeeded = reader.ReadUInt16();
this.diskNumber = reader.ReadUInt32();
this.dirStartDiskNumber = reader.ReadUInt32();
this.entriesOnDisk = reader.ReadInt64();
this.totalEntries = reader.ReadInt64();
this.dirSize = reader.ReadInt64();
this.dirOffset = reader.ReadInt64();
// Ignore any extended zip64 eocd data.
long exDataSize = recordSize + 12 - EOCD64_RECORD_FIXEDSIZE;
if (stream.Length - stream.Position < exDataSize)
{
return false;
}
stream.Seek(exDataSize, SeekOrigin.Current);
this.comment = null;
}
else
{
this.diskNumber = reader.ReadUInt16();
this.dirStartDiskNumber = reader.ReadUInt16();
this.entriesOnDisk = reader.ReadUInt16();
this.totalEntries = reader.ReadUInt16();
this.dirSize = reader.ReadUInt32();
this.dirOffset = reader.ReadUInt32();
int commentLength = reader.ReadUInt16();
if (stream.Length - stream.Position < commentLength)
{
return false;
}
byte[] commentBytes = reader.ReadBytes(commentLength);
this.comment = Encoding.UTF8.GetString(commentBytes);
}
return true;
}
public void Write(Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
if (this.zip64)
{
writer.Write(EOCD64SIG);
writer.Write((long) EOCD64_RECORD_FIXEDSIZE);
writer.Write(this.versionMadeBy);
writer.Write(this.versionNeeded);
writer.Write(this.diskNumber);
writer.Write(this.dirStartDiskNumber);
writer.Write(this.entriesOnDisk);
writer.Write(this.totalEntries);
writer.Write(this.dirSize);
writer.Write(this.dirOffset);
}
else
{
writer.Write(EOCDSIG);
writer.Write((ushort) Math.Min((int) UInt16.MaxValue, this.diskNumber));
writer.Write((ushort) Math.Min((int) UInt16.MaxValue, this.dirStartDiskNumber));
writer.Write((ushort) Math.Min((int) UInt16.MaxValue, this.entriesOnDisk));
writer.Write((ushort) Math.Min((int) UInt16.MaxValue, this.totalEntries));
writer.Write((uint) Math.Min((long) UInt32.MaxValue, this.dirSize));
writer.Write((uint) Math.Min((long) UInt32.MaxValue, this.dirOffset));
byte[] commentBytes = (this.comment != null
? Encoding.UTF8.GetBytes(this.comment) : new byte[0]);
writer.Write((ushort) commentBytes.Length);
writer.Write(commentBytes);
}
}
public int GetSize(bool zip64Size)
{
if (zip64Size)
{
return 56;
}
else
{
int commentSize = (this.comment != null
? Encoding.UTF8.GetByteCount(this.comment) : 0);
return 22 + commentSize;
}
}
}
internal class Zip64EndOfCentralDirectoryLocator
{
public const uint EOCDL64SIG = 0x07064B50;
public const uint EOCDL64_SIZE = 20;
public uint dirStartDiskNumber;
public long dirOffset;
public uint totalDisks;
public bool Read(Stream stream)
{
long startPos = stream.Position;
if (stream.Length - startPos < EOCDL64_SIZE)
{
return false;
}
BinaryReader reader = new BinaryReader(stream);
uint sig = reader.ReadUInt32();
if (sig != EOCDL64SIG)
{
return false;
}
this.dirStartDiskNumber = reader.ReadUInt32();
this.dirOffset = reader.ReadInt64();
this.totalDisks = reader.ReadUInt32();
return true;
}
public void Write(Stream stream)
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(EOCDL64SIG);
writer.Write(this.dirStartDiskNumber);
writer.Write(this.dirOffset);
writer.Write(this.totalDisks);
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
//---------------------------------------------------------------------
// <copyright file="ZipInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
/// <summary>
/// Object representing a zip file on disk; provides access to
/// file-based operations on the zip file.
/// </summary>
/// <remarks>
/// Generally, the methods on this class are much easier to use than the
/// stream-based interfaces provided by the <see cref="ZipEngine"/> class.
/// </remarks>
[Serializable]
public class ZipInfo : ArchiveInfo
{
/// <summary>
/// Creates a new CabinetInfo object representing a zip file in a specified path.
/// </summary>
/// <param name="path">The path to the zip file. When creating a zip file, this file does not
/// necessarily exist yet.</param>
public ZipInfo(string path)
: base(path)
{
}
/// <summary>
/// Initializes a new instance of the CabinetInfo class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected ZipInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Creates a compression engine that does the low-level work for
/// this object.
/// </summary>
/// <returns>A new <see cref="ZipEngine"/> instance.</returns>
/// <remarks>
/// Each instance will be <see cref="CompressionEngine.Dispose()"/>d
/// immediately after use.
/// </remarks>
protected override CompressionEngine CreateCompressionEngine()
{
return new ZipEngine();
}
/// <summary>
/// Gets information about the files contained in the archive.
/// </summary>
/// <returns>A list of <see cref="ZipFileInfo"/> objects, each
/// containing information about a file in the archive.</returns>
public new IList<ZipFileInfo> GetFiles()
{
IList<ArchiveFileInfo> files = base.GetFiles();
List<ZipFileInfo> zipFiles = new List<ZipFileInfo>(files.Count);
foreach (ZipFileInfo zipFile in files) zipFiles.Add(zipFile);
return zipFiles.AsReadOnly();
}
/// <summary>
/// Gets information about the certain files contained in the archive file.
/// </summary>
/// <param name="searchPattern">The search string, such as
/// &quot;*.txt&quot;.</param>
/// <returns>A list of <see cref="ZipFileInfo"/> objects, each containing
/// information about a file in the archive.</returns>
public new IList<ZipFileInfo> GetFiles(string searchPattern)
{
IList<ArchiveFileInfo> files = base.GetFiles(searchPattern);
List<ZipFileInfo> zipFiles = new List<ZipFileInfo>(files.Count);
foreach (ZipFileInfo zipFile in files) zipFiles.Add(zipFile);
return zipFiles.AsReadOnly();
}
}
}

Просмотреть файл

@ -0,0 +1,499 @@
//---------------------------------------------------------------------
// <copyright file="ZipPacker.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.IO.Compression;
using System.Collections.Generic;
using System.Globalization;
public partial class ZipEngine
{
/// <summary>
/// Creates a zip archive or chain of zip archives.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="files">An array of file lists. Each list is
/// compressed into one stream in the archive.</param>
/// <param name="maxArchiveSize">The maximum number of bytes for one archive
/// before the contents are chained to the next archive, or zero for unlimited
/// archive size.</param>
/// <exception cref="ArchiveException">The archive could not be
/// created.</exception>
/// <remarks>
/// The stream context implementation may provide a mapping from the file
/// paths within the archive to the external file paths.
/// </remarks>
public override void Pack(
IPackStreamContext streamContext,
IEnumerable<string> files,
long maxArchiveSize)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
if (files == null)
{
throw new ArgumentNullException("files");
}
lock (this)
{
Stream archiveStream = null;
try
{
this.ResetProgressData();
this.totalArchives = 1;
object forceZip64Value = streamContext.GetOption("forceZip64", null);
bool forceZip64 = Convert.ToBoolean(
forceZip64Value, CultureInfo.InvariantCulture);
// Count the total number of files and bytes to be compressed.
foreach (string file in files)
{
FileAttributes attributes;
DateTime lastWriteTime;
Stream fileStream = streamContext.OpenFileReadStream(
file,
out attributes,
out lastWriteTime);
if (fileStream != null)
{
this.totalFileBytes += fileStream.Length;
this.totalFiles++;
streamContext.CloseFileReadStream(file, fileStream);
}
}
List<ZipFileHeader> fileHeaders = new List<ZipFileHeader>();
this.currentFileNumber = -1;
if (this.currentArchiveName == null)
{
this.mainArchiveName = streamContext.GetArchiveName(0);
this.currentArchiveName = this.mainArchiveName;
if (String.IsNullOrEmpty(this.currentArchiveName))
{
throw new FileNotFoundException("No name provided for archive.");
}
}
this.OnProgress(ArchiveProgressType.StartArchive);
// Compress files one by one, saving header info for each.
foreach (string file in files)
{
ZipFileHeader fileHeader = this.PackOneFile(
streamContext,
file,
maxArchiveSize,
forceZip64,
ref archiveStream);
if (fileHeader != null)
{
fileHeaders.Add(fileHeader);
}
this.currentArchiveTotalBytes = (archiveStream != null ?
archiveStream.Position : 0);
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
}
bool zip64 = forceZip64 || this.totalFiles > UInt16.MaxValue;
// Write the central directory composed of all the file headers.
uint centralDirStartArchiveNumber = 0;
long centralDirStartPosition = 0;
long centralDirSize = 0;
for (int i = 0; i < fileHeaders.Count; i++)
{
ZipFileHeader fileHeader = fileHeaders[i];
int headerSize = fileHeader.GetSize(true);
centralDirSize += headerSize;
this.CheckArchiveWriteStream(
streamContext,
maxArchiveSize,
headerSize,
ref archiveStream);
if (i == 0)
{
centralDirStartArchiveNumber = (uint) this.currentArchiveNumber;
centralDirStartPosition = archiveStream.Position;
}
fileHeader.Write(archiveStream, true);
if (fileHeader.zip64)
{
zip64 = true;
}
}
this.currentArchiveTotalBytes =
(archiveStream != null ? archiveStream.Position : 0);
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
ZipEndOfCentralDirectory eocd = new ZipEndOfCentralDirectory();
eocd.dirStartDiskNumber = centralDirStartArchiveNumber;
eocd.entriesOnDisk = fileHeaders.Count;
eocd.totalEntries = fileHeaders.Count;
eocd.dirSize = centralDirSize;
eocd.dirOffset = centralDirStartPosition;
eocd.comment = this.comment;
Zip64EndOfCentralDirectoryLocator eocdl =
new Zip64EndOfCentralDirectoryLocator();
int maxFooterSize = eocd.GetSize(false);
if (archiveStream != null && (zip64 || archiveStream.Position >
((long) UInt32.MaxValue) - eocd.GetSize(false)))
{
maxFooterSize += eocd.GetSize(true) + (int)
Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE;
zip64 = true;
}
this.CheckArchiveWriteStream(
streamContext,
maxArchiveSize,
maxFooterSize,
ref archiveStream);
eocd.diskNumber = (uint) this.currentArchiveNumber;
if (zip64)
{
eocd.versionMadeBy = 45;
eocd.versionNeeded = 45;
eocd.zip64 = true;
eocdl.dirOffset = archiveStream.Position;
eocdl.dirStartDiskNumber = (uint) this.currentArchiveNumber;
eocdl.totalDisks = (uint) this.currentArchiveNumber + 1;
eocd.Write(archiveStream);
eocdl.Write(archiveStream);
eocd.dirOffset = UInt32.MaxValue;
eocd.dirStartDiskNumber = UInt16.MaxValue;
}
eocd.zip64 = false;
eocd.Write(archiveStream);
this.currentArchiveTotalBytes = archiveStream.Position;
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
}
finally
{
if (archiveStream != null)
{
streamContext.CloseArchiveWriteStream(
this.currentArchiveNumber, this.mainArchiveName, archiveStream);
this.OnProgress(ArchiveProgressType.FinishArchive);
}
}
}
}
/// <summary>
/// Moves to the next archive in the sequence if necessary.
/// </summary>
private void CheckArchiveWriteStream(
IPackStreamContext streamContext,
long maxArchiveSize,
long requiredSize,
ref Stream archiveStream)
{
if (archiveStream != null &&
archiveStream.Length > 0 && maxArchiveSize > 0)
{
long sizeRemaining = maxArchiveSize - archiveStream.Length;
if (sizeRemaining < requiredSize)
{
string nextArchiveName = streamContext.GetArchiveName(
this.currentArchiveNumber + 1);
if (String.IsNullOrEmpty(nextArchiveName))
{
throw new FileNotFoundException("No name provided for archive #" +
this.currentArchiveNumber + 1);
}
this.currentArchiveTotalBytes = archiveStream.Position;
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
streamContext.CloseArchiveWriteStream(
this.currentArchiveNumber,
nextArchiveName,
archiveStream);
archiveStream = null;
this.OnProgress(ArchiveProgressType.FinishArchive);
this.currentArchiveNumber++;
this.totalArchives++;
this.currentArchiveBytesProcessed = 0;
this.currentArchiveTotalBytes = 0;
}
}
if (archiveStream == null)
{
if (this.currentArchiveNumber > 0)
{
this.OnProgress(ArchiveProgressType.StartArchive);
}
archiveStream = streamContext.OpenArchiveWriteStream(
this.currentArchiveNumber, this.mainArchiveName, true, this);
if (archiveStream == null)
{
throw new FileNotFoundException("Stream not provided for archive #" +
this.currentArchiveNumber);
}
}
}
/// <summary>
/// Adds one file to a zip archive in the process of being created.
/// </summary>
private ZipFileHeader PackOneFile(
IPackStreamContext streamContext,
string file,
long maxArchiveSize,
bool forceZip64,
ref Stream archiveStream)
{
Stream fileStream = null;
int headerArchiveNumber = 0;
try
{
// TODO: call GetOption to get compression method for the specific file
ZipCompressionMethod compressionMethod = ZipCompressionMethod.Deflate;
if (this.CompressionLevel == CompressionLevel.None)
{
compressionMethod = ZipCompressionMethod.Store;
}
Converter<Stream, Stream> compressionStreamCreator;
if (!ZipEngine.compressionStreamCreators.TryGetValue(
compressionMethod, out compressionStreamCreator))
{
return null;
}
FileAttributes attributes;
DateTime lastWriteTime;
fileStream = streamContext.OpenFileReadStream(
file, out attributes, out lastWriteTime);
if (fileStream == null)
{
return null;
}
this.currentFileName = file;
this.currentFileNumber++;
this.currentFileTotalBytes = fileStream.Length;
this.currentFileBytesProcessed = 0;
this.OnProgress(ArchiveProgressType.StartFile);
ZipFileInfo fileInfo = new ZipFileInfo(
file,
this.currentArchiveNumber,
attributes,
lastWriteTime,
fileStream.Length,
0,
compressionMethod);
bool zip64 = forceZip64 || fileStream.Length >= (long) UInt32.MaxValue;
ZipFileHeader fileHeader = new ZipFileHeader(fileInfo, zip64);
this.CheckArchiveWriteStream(
streamContext,
maxArchiveSize,
fileHeader.GetSize(false),
ref archiveStream);
long headerPosition = archiveStream.Position;
fileHeader.Write(archiveStream, false);
headerArchiveNumber = this.currentArchiveNumber;
uint crc;
long bytesWritten = this.PackFileBytes(
streamContext,
fileStream,
maxArchiveSize,
compressionStreamCreator,
ref archiveStream,
out crc);
fileHeader.Update(
bytesWritten,
fileStream.Length,
crc,
headerPosition,
headerArchiveNumber);
streamContext.CloseFileReadStream(file, fileStream);
fileStream = null;
// Go back and rewrite the updated file header.
if (this.currentArchiveNumber == headerArchiveNumber)
{
long fileEndPosition = archiveStream.Position;
archiveStream.Seek(headerPosition, SeekOrigin.Begin);
fileHeader.Write(archiveStream, false);
archiveStream.Seek(fileEndPosition, SeekOrigin.Begin);
}
else
{
// The file spanned archives, so temporarily reopen
// the archive where it started.
string headerArchiveName = streamContext.GetArchiveName(
headerArchiveNumber + 1);
Stream headerStream = null;
try
{
headerStream = streamContext.OpenArchiveWriteStream(
headerArchiveNumber, headerArchiveName, false, this);
headerStream.Seek(headerPosition, SeekOrigin.Begin);
fileHeader.Write(headerStream, false);
}
finally
{
if (headerStream != null)
{
streamContext.CloseArchiveWriteStream(
headerArchiveNumber, headerArchiveName, headerStream);
}
}
}
this.OnProgress(ArchiveProgressType.FinishFile);
return fileHeader;
}
finally
{
if (fileStream != null)
{
streamContext.CloseFileReadStream(
this.currentFileName, fileStream);
}
}
}
/// <summary>
/// Writes compressed bytes of one file to the archive,
/// keeping track of the CRC and number of bytes written.
/// </summary>
private long PackFileBytes(
IPackStreamContext streamContext,
Stream fileStream,
long maxArchiveSize,
Converter<Stream, Stream> compressionStreamCreator,
ref Stream archiveStream,
out uint crc)
{
long writeStartPosition = archiveStream.Position;
long bytesWritten = 0;
CrcStream fileCrcStream = new CrcStream(fileStream);
ConcatStream concatStream = new ConcatStream(
delegate(ConcatStream s)
{
Stream sourceStream = s.Source;
bytesWritten += sourceStream.Position - writeStartPosition;
this.CheckArchiveWriteStream(
streamContext,
maxArchiveSize,
1,
ref sourceStream);
writeStartPosition = sourceStream.Position;
s.Source = sourceStream;
});
concatStream.Source = archiveStream;
if (maxArchiveSize > 0)
{
concatStream.SetLength(maxArchiveSize);
}
Stream compressionStream = compressionStreamCreator(concatStream);
try
{
byte[] buf = new byte[4096];
long bytesRemaining = fileStream.Length;
int counter = 0;
while (bytesRemaining > 0)
{
int count = (int) Math.Min(
bytesRemaining, (long) buf.Length);
count = fileCrcStream.Read(buf, 0, count);
if (count <= 0)
{
throw new ZipException(
"Failed to read file: " + this.currentFileName);
}
compressionStream.Write(buf, 0, count);
bytesRemaining -= count;
this.fileBytesProcessed += count;
this.currentFileBytesProcessed += count;
this.currentArchiveTotalBytes = concatStream.Source.Position;
this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes;
if (++counter % 16 == 0) // Report every 64K
{
this.OnProgress(ArchiveProgressType.PartialFile);
}
}
if (compressionStream is DeflateStream)
{
compressionStream.Close();
}
else
{
compressionStream.Flush();
}
}
finally
{
archiveStream = concatStream.Source;
}
bytesWritten += archiveStream.Position - writeStartPosition;
crc = fileCrcStream.Crc;
return bytesWritten;
}
}
}

Просмотреть файл

@ -0,0 +1,346 @@
//---------------------------------------------------------------------
// <copyright file="ZipUnpacker.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression.Zip
{
using System;
using System.IO;
using System.IO.Compression;
using System.Collections.Generic;
public partial class ZipEngine
{
/// <summary>
/// Extracts files from a zip archive or archive chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="fileFilter">An optional predicate that can determine
/// which files to process.</param>
/// <exception cref="ArchiveException">The archive provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public override void Unpack(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
lock (this)
{
IList<ZipFileHeader> allHeaders = this.GetCentralDirectory(streamContext);
if (allHeaders == null)
{
throw new ZipException("Zip central directory not found.");
}
IList<ZipFileHeader> headers = new List<ZipFileHeader>(allHeaders.Count);
foreach (ZipFileHeader header in allHeaders)
{
if (!header.IsDirectory &&
(fileFilter == null || fileFilter(header.fileName)))
{
headers.Add(header);
}
}
this.ResetProgressData();
// Count the total number of files and bytes to be compressed.
this.totalFiles = headers.Count;
foreach (ZipFileHeader header in headers)
{
long compressedSize;
long uncompressedSize;
long localHeaderOffset;
int archiveNumber;
uint crc;
header.GetZip64Fields(
out compressedSize,
out uncompressedSize,
out localHeaderOffset,
out archiveNumber,
out crc);
this.totalFileBytes += uncompressedSize;
if (archiveNumber >= this.totalArchives)
{
this.totalArchives = (short) (archiveNumber + 1);
}
}
this.currentArchiveNumber = -1;
this.currentFileNumber = -1;
Stream archiveStream = null;
try
{
foreach (ZipFileHeader header in headers)
{
this.currentFileNumber++;
this.UnpackOneFile(streamContext, header, ref archiveStream);
}
}
finally
{
if (archiveStream != null)
{
streamContext.CloseArchiveReadStream(
0, String.Empty, archiveStream);
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.FinishArchive);
}
}
}
}
/// <summary>
/// Unpacks a single file from an archive or archive chain.
/// </summary>
private void UnpackOneFile(
IUnpackStreamContext streamContext,
ZipFileHeader header,
ref Stream archiveStream)
{
ZipFileInfo fileInfo = null;
Stream fileStream = null;
try
{
Converter<Stream, Stream> compressionStreamCreator;
if (!ZipEngine.decompressionStreamCreators.TryGetValue(
header.compressionMethod, out compressionStreamCreator))
{
// Silently skip files of an unsupported compression method.
return;
}
long compressedSize;
long uncompressedSize;
long localHeaderOffset;
int archiveNumber;
uint crc;
header.GetZip64Fields(
out compressedSize,
out uncompressedSize,
out localHeaderOffset,
out archiveNumber,
out crc);
if (this.currentArchiveNumber != archiveNumber + 1)
{
if (archiveStream != null)
{
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber,
String.Empty,
archiveStream);
archiveStream = null;
this.OnProgress(ArchiveProgressType.FinishArchive);
this.currentArchiveName = null;
}
this.currentArchiveNumber = (short) (archiveNumber + 1);
this.currentArchiveBytesProcessed = 0;
this.currentArchiveTotalBytes = 0;
archiveStream = this.OpenArchive(
streamContext, this.currentArchiveNumber);
FileStream archiveFileStream = archiveStream as FileStream;
this.currentArchiveName = (archiveFileStream != null ?
Path.GetFileName(archiveFileStream.Name) : null);
this.currentArchiveTotalBytes = archiveStream.Length;
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.StartArchive);
this.currentArchiveNumber++;
}
archiveStream.Seek(localHeaderOffset, SeekOrigin.Begin);
ZipFileHeader localHeader = new ZipFileHeader();
if (!localHeader.Read(archiveStream, false) ||
!ZipEngine.AreFilePathsEqual(localHeader.fileName, header.fileName))
{
string msg = "Could not read file: " + header.fileName;
throw new ZipException(msg);
}
fileInfo = header.ToZipFileInfo();
fileStream = streamContext.OpenFileWriteStream(
fileInfo.FullName,
fileInfo.Length,
fileInfo.LastWriteTime);
if (fileStream != null)
{
this.currentFileName = header.fileName;
this.currentFileBytesProcessed = 0;
this.currentFileTotalBytes = fileInfo.Length;
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.StartFile);
this.currentArchiveNumber++;
this.UnpackFileBytes(
streamContext,
fileInfo.FullName,
fileInfo.CompressedLength,
fileInfo.Length,
header.crc32,
fileStream,
compressionStreamCreator,
ref archiveStream);
}
}
finally
{
if (fileStream != null)
{
streamContext.CloseFileWriteStream(
fileInfo.FullName,
fileStream,
fileInfo.Attributes,
fileInfo.LastWriteTime);
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.FinishFile);
this.currentArchiveNumber++;
}
}
}
/// <summary>
/// Compares two internal file paths while ignoring case and slash differences.
/// </summary>
/// <param name="path1">The first path to compare.</param>
/// <param name="path2">The second path to compare.</param>
/// <returns>True if the paths are equivalent.</returns>
private static bool AreFilePathsEqual(string path1, string path2)
{
path1 = path1.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
path2 = path2.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
return String.Compare(path1, path2, StringComparison.OrdinalIgnoreCase) == 0;
}
private Stream OpenArchive(IUnpackStreamContext streamContext, int archiveNumber)
{
Stream archiveStream = streamContext.OpenArchiveReadStream(
archiveNumber, String.Empty, this);
if (archiveStream == null && archiveNumber != 0)
{
archiveStream = streamContext.OpenArchiveReadStream(
0, String.Empty, this);
}
if (archiveStream == null)
{
throw new FileNotFoundException("Archive stream not provided.");
}
return archiveStream;
}
/// <summary>
/// Decompresses bytes for one file from an archive or archive chain,
/// checking the crc at the end.
/// </summary>
private void UnpackFileBytes(
IUnpackStreamContext streamContext,
string fileName,
long compressedSize,
long uncompressedSize,
uint crc,
Stream fileStream,
Converter<Stream, Stream> compressionStreamCreator,
ref Stream archiveStream)
{
CrcStream crcStream = new CrcStream(fileStream);
ConcatStream concatStream = new ConcatStream(
delegate(ConcatStream s)
{
this.currentArchiveBytesProcessed = s.Source.Position;
streamContext.CloseArchiveReadStream(
this.currentArchiveNumber,
String.Empty,
s.Source);
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.FinishArchive);
this.currentArchiveNumber += 2;
this.currentArchiveName = null;
this.currentArchiveBytesProcessed = 0;
this.currentArchiveTotalBytes = 0;
s.Source = this.OpenArchive(streamContext, this.currentArchiveNumber);
FileStream archiveFileStream = s.Source as FileStream;
this.currentArchiveName = (archiveFileStream != null ?
Path.GetFileName(archiveFileStream.Name) : null);
this.currentArchiveTotalBytes = s.Source.Length;
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.StartArchive);
this.currentArchiveNumber++;
});
concatStream.Source = archiveStream;
concatStream.SetLength(compressedSize);
Stream decompressionStream = compressionStreamCreator(concatStream);
try
{
byte[] buf = new byte[4096];
long bytesRemaining = uncompressedSize;
int counter = 0;
while (bytesRemaining > 0)
{
int count = (int) Math.Min(buf.Length, bytesRemaining);
count = decompressionStream.Read(buf, 0, count);
crcStream.Write(buf, 0, count);
bytesRemaining -= count;
this.fileBytesProcessed += count;
this.currentFileBytesProcessed += count;
this.currentArchiveBytesProcessed = concatStream.Source.Position;
if (++counter % 16 == 0) // Report every 64K
{
this.currentArchiveNumber--;
this.OnProgress(ArchiveProgressType.PartialFile);
this.currentArchiveNumber++;
}
}
}
finally
{
archiveStream = concatStream.Source;
}
crcStream.Flush();
if (crcStream.Crc != crc)
{
throw new ZipException("CRC check failed for file: " + fileName);
}
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveException.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Runtime.Serialization;
/// <summary>
/// Base exception class for compression operations. Compression libraries should
/// derive subclass exceptions with more specific error information relevent to the
/// file format.
/// </summary>
[Serializable]
public class ArchiveException : IOException
{
/// <summary>
/// Creates a new ArchiveException with a specified error message and a reference to the
/// inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If the
/// innerException parameter is not a null reference (Nothing in Visual Basic), the current exception
/// is raised in a catch block that handles the inner exception.</param>
public ArchiveException(string message, Exception innerException)
: base(message, innerException)
{
}
/// <summary>
/// Creates a new ArchiveException with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ArchiveException(string message)
: this(message, null)
{
}
/// <summary>
/// Creates a new ArchiveException.
/// </summary>
public ArchiveException()
: this(null, null)
{
}
/// <summary>
/// Initializes a new instance of the ArchiveException class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
protected ArchiveException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

Просмотреть файл

@ -0,0 +1,442 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveFileInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Abstract object representing a compressed file within an archive;
/// provides operations for getting the file properties and unpacking
/// the file.
/// </summary>
[Serializable]
public abstract class ArchiveFileInfo : FileSystemInfo
{
private ArchiveInfo archiveInfo;
private string name;
private string path;
private bool initialized;
private bool exists;
private int archiveNumber;
private FileAttributes attributes;
private DateTime lastWriteTime;
private long length;
/// <summary>
/// Creates a new ArchiveFileInfo object representing a file within
/// an archive in a specified path.
/// </summary>
/// <param name="archiveInfo">An object representing the archive
/// containing the file.</param>
/// <param name="filePath">The path to the file within the archive.
/// Usually, this is a simple file name, but if the archive contains
/// a directory structure this may include the directory.</param>
protected ArchiveFileInfo(ArchiveInfo archiveInfo, string filePath)
: base()
{
if (filePath == null)
{
throw new ArgumentNullException("filePath");
}
this.Archive = archiveInfo;
this.name = System.IO.Path.GetFileName(filePath);
this.path = System.IO.Path.GetDirectoryName(filePath);
this.attributes = FileAttributes.Normal;
this.lastWriteTime = DateTime.MinValue;
}
/// <summary>
/// Creates a new ArchiveFileInfo object with all parameters specified;
/// used by subclasses when reading the metadata out of an archive.
/// </summary>
/// <param name="filePath">The internal path and name of the file in
/// the archive.</param>
/// <param name="archiveNumber">The archive number where the file
/// starts.</param>
/// <param name="attributes">The stored attributes of the file.</param>
/// <param name="lastWriteTime">The stored last write time of the
/// file.</param>
/// <param name="length">The uncompressed size of the file.</param>
protected ArchiveFileInfo(
string filePath,
int archiveNumber,
FileAttributes attributes,
DateTime lastWriteTime,
long length)
: this(null, filePath)
{
this.exists = true;
this.archiveNumber = archiveNumber;
this.attributes = attributes;
this.lastWriteTime = lastWriteTime;
this.length = length;
this.initialized = true;
}
/// <summary>
/// Initializes a new instance of the ArchiveFileInfo class with
/// serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized
/// object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual
/// information about the source or destination.</param>
protected ArchiveFileInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.archiveInfo = (ArchiveInfo) info.GetValue(
"archiveInfo", typeof(ArchiveInfo));
this.name = info.GetString("name");
this.path = info.GetString("path");
this.initialized = info.GetBoolean("initialized");
this.exists = info.GetBoolean("exists");
this.archiveNumber = info.GetInt32("archiveNumber");
this.attributes = (FileAttributes) info.GetValue(
"attributes", typeof(FileAttributes));
this.lastWriteTime = info.GetDateTime("lastWriteTime");
this.length = info.GetInt64("length");
}
/// <summary>
/// Gets the name of the file.
/// </summary>
/// <value>The name of the file, not including any path.</value>
public override string Name
{
get
{
return this.name;
}
}
/// <summary>
/// Gets the internal path of the file in the archive.
/// </summary>
/// <value>The internal path of the file in the archive, not including
/// the file name.</value>
public string Path
{
get
{
return this.path;
}
}
/// <summary>
/// Gets the full path to the file.
/// </summary>
/// <value>The full path to the file, including the full path to the
/// archive, the internal path in the archive, and the file name.</value>
/// <remarks>
/// For example, the path <c>"C:\archive.cab\file.txt"</c> refers to
/// a file "file.txt" inside the archive "archive.cab".
/// </remarks>
public override string FullName
{
get
{
string fullName = System.IO.Path.Combine(this.Path, this.Name);
if (this.Archive != null)
{
fullName = System.IO.Path.Combine(this.ArchiveName, fullName);
}
return fullName;
}
}
/// <summary>
/// Gets or sets the archive that contains this file.
/// </summary>
/// <value>
/// The ArchiveInfo instance that retrieved this file information -- this
/// may be null if the ArchiveFileInfo object was returned directly from
/// a stream.
/// </value>
public ArchiveInfo Archive
{
get
{
return (ArchiveInfo) this.archiveInfo;
}
internal set
{
this.archiveInfo = value;
// protected instance members inherited from FileSystemInfo:
this.OriginalPath = (value != null ? value.FullName : null);
this.FullPath = this.OriginalPath;
}
}
/// <summary>
/// Gets the full path of the archive that contains this file.
/// </summary>
/// <value>The full path of the archive that contains this file.</value>
public string ArchiveName
{
get
{
return this.Archive != null ? this.Archive.FullName : null;
}
}
/// <summary>
/// Gets the number of the archive where this file starts.
/// </summary>
/// <value>The number of the archive where this file starts.</value>
/// <remarks>A single archive or the first archive in a chain is
/// numbered 0.</remarks>
public int ArchiveNumber
{
get
{
return this.archiveNumber;
}
}
/// <summary>
/// Checks if the file exists within the archive.
/// </summary>
/// <value>True if the file exists, false otherwise.</value>
public override bool Exists
{
get
{
if (!this.initialized)
{
this.Refresh();
}
return this.exists;
}
}
/// <summary>
/// Gets the uncompressed size of the file.
/// </summary>
/// <value>The uncompressed size of the file in bytes.</value>
public long Length
{
get
{
if (!this.initialized)
{
this.Refresh();
}
return this.length;
}
}
/// <summary>
/// Gets the attributes of the file.
/// </summary>
/// <value>The attributes of the file as stored in the archive.</value>
public new FileAttributes Attributes
{
get
{
if (!this.initialized)
{
this.Refresh();
}
return this.attributes;
}
}
/// <summary>
/// Gets the last modification time of the file.
/// </summary>
/// <value>The last modification time of the file as stored in the
/// archive.</value>
public new DateTime LastWriteTime
{
get
{
if (!this.initialized)
{
this.Refresh();
}
return this.lastWriteTime;
}
}
/// <summary>
/// Sets the SerializationInfo with information about the archive.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized
/// object data.</param>
/// <param name="context">The StreamingContext that contains contextual
/// information about the source or destination.</param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(
SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("archiveInfo", this.archiveInfo);
info.AddValue("name", this.name);
info.AddValue("path", this.path);
info.AddValue("initialized", this.initialized);
info.AddValue("exists", this.exists);
info.AddValue("archiveNumber", this.archiveNumber);
info.AddValue("attributes", this.attributes);
info.AddValue("lastWriteTime", this.lastWriteTime);
info.AddValue("length", this.length);
}
/// <summary>
/// Gets the full path to the file.
/// </summary>
/// <returns>The same as <see cref="FullName"/></returns>
public override string ToString()
{
return this.FullName;
}
/// <summary>
/// Deletes the file. NOT SUPPORTED.
/// </summary>
/// <exception cref="NotSupportedException">Files cannot be deleted
/// from an existing archive.</exception>
public override void Delete()
{
throw new NotSupportedException();
}
/// <summary>
/// Refreshes the attributes and other cached information about the file,
/// by re-reading the information from the archive.
/// </summary>
public new void Refresh()
{
base.Refresh();
if (this.Archive != null)
{
string filePath = System.IO.Path.Combine(this.Path, this.Name);
ArchiveFileInfo updatedFile = this.Archive.GetFile(filePath);
if (updatedFile == null)
{
throw new FileNotFoundException(
"File not found in archive.", filePath);
}
this.Refresh(updatedFile);
}
}
/// <summary>
/// Extracts the file.
/// </summary>
/// <param name="destFileName">The destination path where the file
/// will be extracted.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void CopyTo(string destFileName)
{
this.CopyTo(destFileName, false);
}
/// <summary>
/// Extracts the file, optionally overwriting any existing file.
/// </summary>
/// <param name="destFileName">The destination path where the file
/// will be extracted.</param>
/// <param name="overwrite">If true, <paramref name="destFileName"/>
/// will be overwritten if it exists.</param>
/// <exception cref="IOException"><paramref name="overwrite"/> is false
/// and <paramref name="destFileName"/> exists.</exception>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void CopyTo(string destFileName, bool overwrite)
{
if (destFileName == null)
{
throw new ArgumentNullException("destFileName");
}
if (!overwrite && File.Exists(destFileName))
{
throw new IOException();
}
if (this.Archive == null)
{
throw new InvalidOperationException();
}
this.Archive.UnpackFile(
System.IO.Path.Combine(this.Path, this.Name), destFileName);
}
/// <summary>
/// Opens the archive file for reading without actually extracting the
/// file to disk.
/// </summary>
/// <returns>
/// A stream for reading directly from the packed file. Like any stream
/// this should be closed/disposed as soon as it is no longer needed.
/// </returns>
public Stream OpenRead()
{
return this.Archive.OpenRead(System.IO.Path.Combine(this.Path, this.Name));
}
/// <summary>
/// Opens the archive file reading text with UTF-8 encoding without
/// actually extracting the file to disk.
/// </summary>
/// <returns>
/// A reader for reading text directly from the packed file. Like any reader
/// this should be closed/disposed as soon as it is no longer needed.
/// </returns>
/// <remarks>
/// To open an archived text file with different encoding, use the
/// <see cref="OpenRead" /> method and pass the returned stream to one of
/// the <see cref="StreamReader" /> constructor overloads.
/// </remarks>
public StreamReader OpenText()
{
return this.Archive.OpenText(System.IO.Path.Combine(this.Path, this.Name));
}
/// <summary>
/// Refreshes the information in this object with new data retrieved
/// from an archive.
/// </summary>
/// <param name="newFileInfo">Fresh instance for the same file just
/// read from the archive.</param>
/// <remarks>
/// Subclasses may override this method to refresh sublcass fields.
/// However they should always call the base implementation first.
/// </remarks>
protected virtual void Refresh(ArchiveFileInfo newFileInfo)
{
this.exists = newFileInfo.exists;
this.length = newFileInfo.length;
this.attributes = newFileInfo.attributes;
this.lastWriteTime = newFileInfo.lastWriteTime;
}
}
}

Просмотреть файл

@ -0,0 +1,662 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveFileStreamContext.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Collections.Generic;
/// <summary>
/// Provides a basic implementation of the archive pack and unpack stream context
/// interfaces, based on a list of archive files, a default directory, and an
/// optional mapping from internal to external file paths.
/// </summary>
/// <remarks>
/// This class can also handle creating or extracting chained archive packages.
/// </remarks>
public class ArchiveFileStreamContext
: IPackStreamContext, IUnpackStreamContext
{
private IList<string> archiveFiles;
private string directory;
private IDictionary<string, string> files;
private bool extractOnlyNewerFiles;
private bool enableOffsetOpen;
#region Constructors
/// <summary>
/// Creates a new ArchiveFileStreamContext with a archive file and
/// no default directory or file mapping.
/// </summary>
/// <param name="archiveFile">The path to a archive file that will be
/// created or extracted.</param>
public ArchiveFileStreamContext(string archiveFile)
: this(archiveFile, null, null)
{
}
/// <summary>
/// Creates a new ArchiveFileStreamContext with a archive file, default
/// directory and mapping from internal to external file paths.
/// </summary>
/// <param name="archiveFile">The path to a archive file that will be
/// created or extracted.</param>
/// <param name="directory">The default root directory where files will be
/// located, optional.</param>
/// <param name="files">A mapping from internal file paths to external file
/// paths, optional.</param>
/// <remarks>
/// If the mapping is not null and a file is not included in the mapping,
/// the file will be skipped.
/// <para>If the external path in the mapping is a simple file name or
/// relative file path, it will be concatenated onto the default directory,
/// if one was specified.</para>
/// <para>For more about how the default directory and files mapping are
/// used, see <see cref="OpenFileReadStream"/> and
/// <see cref="OpenFileWriteStream"/>.</para>
/// </remarks>
public ArchiveFileStreamContext(
string archiveFile,
string directory,
IDictionary<string, string> files)
: this(new string[] { archiveFile }, directory, files)
{
if (archiveFile == null)
{
throw new ArgumentNullException("archiveFile");
}
}
/// <summary>
/// Creates a new ArchiveFileStreamContext with a list of archive files,
/// a default directory and a mapping from internal to external file paths.
/// </summary>
/// <param name="archiveFiles">A list of paths to archive files that will be
/// created or extracted.</param>
/// <param name="directory">The default root directory where files will be
/// located, optional.</param>
/// <param name="files">A mapping from internal file paths to external file
/// paths, optional.</param>
/// <remarks>
/// When creating chained archives, the <paramref name="archiveFiles"/> list
/// should include at least enough archives to handle the entire set of
/// input files, based on the maximum archive size that is passed to the
/// <see cref="CompressionEngine"/>.<see
/// cref="CompressionEngine.Pack(IPackStreamContext,IEnumerable&lt;string&gt;,long)"/>.
/// <para>If the mapping is not null and a file is not included in the mapping,
/// the file will be skipped.</para>
/// <para>If the external path in the mapping is a simple file name or
/// relative file path, it will be concatenated onto the default directory,
/// if one was specified.</para>
/// <para>For more about how the default directory and files mapping are used,
/// see <see cref="OpenFileReadStream"/> and
/// <see cref="OpenFileWriteStream"/>.</para>
/// </remarks>
public ArchiveFileStreamContext(
IList<string> archiveFiles,
string directory,
IDictionary<string, string> files)
{
if (archiveFiles == null || archiveFiles.Count == 0)
{
throw new ArgumentNullException("archiveFiles");
}
this.archiveFiles = archiveFiles;
this.directory = directory;
this.files = files;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the list of archive files that are created or extracted.
/// </summary>
/// <value>The list of archive files that are created or extracted.</value>
public IList<string> ArchiveFiles
{
get
{
return this.archiveFiles;
}
}
/// <summary>
/// Gets or sets the default root directory where files are located.
/// </summary>
/// <value>The default root directory where files are located.</value>
/// <remarks>
/// For details about how the default directory is used,
/// see <see cref="OpenFileReadStream"/> and <see cref="OpenFileWriteStream"/>.
/// </remarks>
public string Directory
{
get
{
return this.directory;
}
}
/// <summary>
/// Gets or sets the mapping from internal file paths to external file paths.
/// </summary>
/// <value>A mapping from internal file paths to external file paths.</value>
/// <remarks>
/// For details about how the files mapping is used,
/// see <see cref="OpenFileReadStream"/> and <see cref="OpenFileWriteStream"/>.
/// </remarks>
public IDictionary<string, string> Files
{
get
{
return this.files;
}
}
/// <summary>
/// Gets or sets a flag that can prevent extracted files from overwriting
/// newer files that already exist.
/// </summary>
/// <value>True to prevent overwriting newer files that already exist
/// during extraction; false to always extract from the archive regardless
/// of existing files.</value>
public bool ExtractOnlyNewerFiles
{
get
{
return this.extractOnlyNewerFiles;
}
set
{
this.extractOnlyNewerFiles = value;
}
}
/// <summary>
/// Gets or sets a flag that enables creating or extracting an archive
/// at an offset within an existing file. (This is typically used to open
/// archive-based self-extracting packages.)
/// </summary>
/// <value>True to search an existing package file for an archive offset
/// or the end of the file;/ false to always create or open a plain
/// archive file.</value>
public bool EnableOffsetOpen
{
get
{
return this.enableOffsetOpen;
}
set
{
this.enableOffsetOpen = value;
}
}
#endregion
#region IPackStreamContext Members
/// <summary>
/// Gets the name of the archive with a specified number.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive within
/// the chain.</param>
/// <returns>The name of the requested archive. May be an empty string
/// for non-chained archives, but may never be null.</returns>
/// <remarks>This method returns the file name of the archive from the
/// <see cref="archiveFiles"/> list with the specified index, or an empty
/// string if the archive number is outside the bounds of the list. The
/// file name should not include any directory path.</remarks>
public virtual string GetArchiveName(int archiveNumber)
{
if (archiveNumber < this.archiveFiles.Count)
{
return Path.GetFileName(this.archiveFiles[archiveNumber]);
}
return String.Empty;
}
/// <summary>
/// Opens a stream for writing an archive.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive within
/// the chain.</param>
/// <param name="archiveName">The name of the archive that was returned
/// by <see cref="GetArchiveName"/>.</param>
/// <param name="truncate">True if the stream should be truncated when
/// opened (if it already exists); false if an existing stream is being
/// re-opened for writing additional data.</param>
/// <param name="compressionEngine">Instance of the compression engine
/// doing the operations.</param>
/// <returns>A writable Stream where the compressed archive bytes will be
/// written, or null to cancel the archive creation.</returns>
/// <remarks>
/// This method opens the file from the <see cref="ArchiveFiles"/> list
/// with the specified index. If the archive number is outside the bounds
/// of the list, this method returns null.
/// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method
/// will seek to the start of any existing archive in the file, or to the
/// end of the file if the existing file is not an archive.</para>
/// </remarks>
public virtual Stream OpenArchiveWriteStream(
int archiveNumber,
string archiveName,
bool truncate,
CompressionEngine compressionEngine)
{
if (archiveNumber >= this.archiveFiles.Count)
{
return null;
}
if (String.IsNullOrEmpty(archiveName))
{
throw new ArgumentNullException("archiveName");
}
// All archives must be in the same directory,
// so always use the directory from the first archive.
string archiveFile = Path.Combine(
Path.GetDirectoryName(this.archiveFiles[0]), archiveName);
Stream stream = File.Open(
archiveFile,
(truncate ? FileMode.OpenOrCreate : FileMode.Open),
FileAccess.ReadWrite);
if (this.enableOffsetOpen)
{
long offset = compressionEngine.FindArchiveOffset(
new DuplicateStream(stream));
// If this is not an archive file, append the archive to it.
if (offset < 0)
{
offset = stream.Length;
}
if (offset > 0)
{
stream = new OffsetStream(stream, offset);
}
stream.Seek(0, SeekOrigin.Begin);
}
if (truncate)
{
// Truncate the stream, in case a larger old archive starts here.
stream.SetLength(0);
}
return stream;
}
/// <summary>
/// Closes a stream where an archive package was written.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive within
/// the chain.</param>
/// <param name="archiveName">The name of the archive that was previously
/// returned by <see cref="GetArchiveName"/>.</param>
/// <param name="stream">A stream that was previously returned by
/// <see cref="OpenArchiveWriteStream"/> and is now ready to be closed.</param>
public virtual void CloseArchiveWriteStream(
int archiveNumber,
string archiveName,
Stream stream)
{
if (stream != null)
{
stream.Close();
FileStream fileStream = stream as FileStream;
if (fileStream != null)
{
string streamFile = fileStream.Name;
if (!String.IsNullOrEmpty(archiveName) &&
archiveName != Path.GetFileName(streamFile))
{
string archiveFile = Path.Combine(
Path.GetDirectoryName(this.archiveFiles[0]), archiveName);
if (File.Exists(archiveFile))
{
File.Delete(archiveFile);
}
File.Move(streamFile, archiveFile);
}
}
}
}
/// <summary>
/// Opens a stream to read a file that is to be included in an archive.
/// </summary>
/// <param name="path">The path of the file within the archive.</param>
/// <param name="attributes">The returned attributes of the opened file,
/// to be stored in the archive.</param>
/// <param name="lastWriteTime">The returned last-modified time of the
/// opened file, to be stored in the archive.</param>
/// <returns>A readable Stream where the file bytes will be read from
/// before they are compressed, or null to skip inclusion of the file and
/// continue to the next file.</returns>
/// <remarks>
/// This method opens a file using the following logic:
/// <list>
/// <item>If the <see cref="Directory"/> and the <see cref="Files"/> mapping
/// are both null, the path is treated as relative to the current directory,
/// and that file is opened.</item>
/// <item>If the <see cref="Directory"/> is not null but the <see cref="Files"/>
/// mapping is null, the path is treated as relative to that directory, and
/// that file is opened.</item>
/// <item>If the <see cref="Directory"/> is null but the <see cref="Files"/>
/// mapping is not null, the path parameter is used as a key into the mapping,
/// and the resulting value is the file path that is opened, relative to the
/// current directory (or it may be an absolute path). If no mapping exists,
/// the file is skipped.</item>
/// <item>If both the <see cref="Directory"/> and the <see cref="Files"/>
/// mapping are specified, the path parameter is used as a key into the
/// mapping, and the resulting value is the file path that is opened, relative
/// to the specified directory (or it may be an absolute path). If no mapping
/// exists, the file is skipped.</item>
/// </list>
/// </remarks>
public virtual Stream OpenFileReadStream(
string path, out FileAttributes attributes, out DateTime lastWriteTime)
{
string filePath = this.TranslateFilePath(path);
if (filePath == null)
{
attributes = FileAttributes.Normal;
lastWriteTime = DateTime.Now;
return null;
}
attributes = File.GetAttributes(filePath);
lastWriteTime = File.GetLastWriteTime(filePath);
return File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
/// <summary>
/// Closes a stream that has been used to read a file.
/// </summary>
/// <param name="path">The path of the file within the archive; the same as
/// the path provided when the stream was opened.</param>
/// <param name="stream">A stream that was previously returned by
/// <see cref="OpenFileReadStream"/> and is now ready to be closed.</param>
public virtual void CloseFileReadStream(string path, Stream stream)
{
if (stream != null)
{
stream.Close();
}
}
/// <summary>
/// Gets extended parameter information specific to the compression format
/// being used.
/// </summary>
/// <param name="optionName">Name of the option being requested.</param>
/// <param name="parameters">Parameters for the option; for per-file options,
/// the first parameter is typically the internal file path.</param>
/// <returns>Option value, or null to use the default behavior.</returns>
/// <remarks>
/// This implementation does not handle any options. Subclasses may override
/// this method to allow for non-default behavior.
/// </remarks>
public virtual object GetOption(string optionName, object[] parameters)
{
return null;
}
#endregion
#region IUnpackStreamContext Members
/// <summary>
/// Opens the archive stream for reading.
/// </summary>
/// <param name="archiveNumber">The zero-based index of the archive to
/// open.</param>
/// <param name="archiveName">The name of the archive being opened.</param>
/// <param name="compressionEngine">Instance of the compression engine
/// doing the operations.</param>
/// <returns>A stream from which archive bytes are read, or null to cancel
/// extraction of the archive.</returns>
/// <remarks>
/// This method opens the file from the <see cref="ArchiveFiles"/> list with
/// the specified index. If the archive number is outside the bounds of the
/// list, this method returns null.
/// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method will
/// seek to the start of any existing archive in the file, or to the end of
/// the file if the existing file is not an archive.</para>
/// </remarks>
public virtual Stream OpenArchiveReadStream(
int archiveNumber, string archiveName, CompressionEngine compressionEngine)
{
if (archiveNumber >= this.archiveFiles.Count)
{
return null;
}
string archiveFile = this.archiveFiles[archiveNumber];
Stream stream = File.Open(
archiveFile, FileMode.Open, FileAccess.Read, FileShare.Read);
if (this.enableOffsetOpen)
{
long offset = compressionEngine.FindArchiveOffset(
new DuplicateStream(stream));
if (offset > 0)
{
stream = new OffsetStream(stream, offset);
}
else
{
stream.Seek(0, SeekOrigin.Begin);
}
}
return stream;
}
/// <summary>
/// Closes a stream where an archive was read.
/// </summary>
/// <param name="archiveNumber">The archive number of the stream
/// to close.</param>
/// <param name="archiveName">The name of the archive being closed.</param>
/// <param name="stream">The stream that was previously returned by
/// <see cref="OpenArchiveReadStream"/> and is now ready to be closed.</param>
public virtual void CloseArchiveReadStream(
int archiveNumber, string archiveName, Stream stream)
{
if (stream != null)
{
stream.Close();
}
}
/// <summary>
/// Opens a stream for writing extracted file bytes.
/// </summary>
/// <param name="path">The path of the file within the archive.</param>
/// <param name="fileSize">The uncompressed size of the file to be
/// extracted.</param>
/// <param name="lastWriteTime">The last write time of the file to be
/// extracted.</param>
/// <returns>A stream where extracted file bytes are to be written, or null
/// to skip extraction of the file and continue to the next file.</returns>
/// <remarks>
/// This method opens a file using the following logic:
/// <list>
/// <item>If the <see cref="Directory"/> and the <see cref="Files"/> mapping
/// are both null, the path is treated as relative to the current directory,
/// and that file is opened.</item>
/// <item>If the <see cref="Directory"/> is not null but the <see cref="Files"/>
/// mapping is null, the path is treated as relative to that directory, and
/// that file is opened.</item>
/// <item>If the <see cref="Directory"/> is null but the <see cref="Files"/>
/// mapping is not null, the path parameter is used as a key into the mapping,
/// and the resulting value is the file path that is opened, relative to the
/// current directory (or it may be an absolute path). If no mapping exists,
/// the file is skipped.</item>
/// <item>If both the <see cref="Directory"/> and the <see cref="Files"/>
/// mapping are specified, the path parameter is used as a key into the
/// mapping, and the resulting value is the file path that is opened,
/// relative to the specified directory (or it may be an absolute path).
/// If no mapping exists, the file is skipped.</item>
/// </list>
/// <para>If the <see cref="ExtractOnlyNewerFiles"/> flag is set, the file
/// is skipped if a file currently exists in the same path with an equal
/// or newer write time.</para>
/// </remarks>
public virtual Stream OpenFileWriteStream(
string path,
long fileSize,
DateTime lastWriteTime)
{
string filePath = this.TranslateFilePath(path);
if (filePath == null)
{
return null;
}
FileInfo file = new FileInfo(filePath);
if (file.Exists)
{
if (this.extractOnlyNewerFiles && lastWriteTime != DateTime.MinValue)
{
if (file.LastWriteTime >= lastWriteTime)
{
return null;
}
}
// Clear attributes that will prevent overwriting the file.
// (The final attributes will be set after the file is unpacked.)
FileAttributes attributesToClear =
FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System;
if ((file.Attributes & attributesToClear) != 0)
{
file.Attributes &= ~attributesToClear;
}
}
if (!file.Directory.Exists)
{
file.Directory.Create();
}
return File.Open(
filePath, FileMode.Create, FileAccess.Write, FileShare.None);
}
/// <summary>
/// Closes a stream where an extracted file was written.
/// </summary>
/// <param name="path">The path of the file within the archive.</param>
/// <param name="stream">The stream that was previously returned by
/// <see cref="OpenFileWriteStream"/> and is now ready to be closed.</param>
/// <param name="attributes">The attributes of the extracted file.</param>
/// <param name="lastWriteTime">The last write time of the file.</param>
/// <remarks>
/// After closing the extracted file stream, this method applies the date
/// and attributes to that file.
/// </remarks>
public virtual void CloseFileWriteStream(
string path,
Stream stream,
FileAttributes attributes,
DateTime lastWriteTime)
{
if (stream != null)
{
stream.Close();
}
string filePath = this.TranslateFilePath(path);
if (filePath != null)
{
FileInfo file = new FileInfo(filePath);
if (lastWriteTime != DateTime.MinValue)
{
try
{
file.LastWriteTime = lastWriteTime;
}
catch (ArgumentException)
{
}
catch (IOException)
{
}
}
try
{
file.Attributes = attributes;
}
catch (IOException)
{
}
}
}
#endregion
#region Private utility methods
/// <summary>
/// Translates an internal file path to an external file path using the
/// <see cref="Directory"/> and the <see cref="Files"/> mapping, according to
/// rules documented in <see cref="OpenFileReadStream"/> and
/// <see cref="OpenFileWriteStream"/>.
/// </summary>
/// <param name="path">The path of the file with the archive.</param>
/// <returns>The external path of the file, or null if there is no
/// valid translation.</returns>
private string TranslateFilePath(string path)
{
string filePath;
if (this.files != null)
{
filePath = this.files[path];
}
else
{
filePath = path;
}
if (filePath != null)
{
if (this.directory != null)
{
filePath = Path.Combine(this.directory, filePath);
}
}
return filePath;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,792 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Abstract object representing a compressed archive on disk;
/// provides access to file-based operations on the archive.
/// </summary>
[Serializable]
public abstract class ArchiveInfo : FileSystemInfo
{
/// <summary>
/// Creates a new ArchiveInfo object representing an archive in a
/// specified path.
/// </summary>
/// <param name="path">The path to the archive. When creating an archive,
/// this file does not necessarily exist yet.</param>
protected ArchiveInfo(string path) : base()
{
if (path == null)
{
throw new ArgumentNullException("path");
}
// protected instance members inherited from FileSystemInfo:
this.OriginalPath = path;
this.FullPath = Path.GetFullPath(path);
}
/// <summary>
/// Initializes a new instance of the ArchiveInfo class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object
/// data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual
/// information about the source or destination.</param>
protected ArchiveInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Gets the directory that contains the archive.
/// </summary>
/// <value>A DirectoryInfo object representing the parent directory of the
/// archive.</value>
public DirectoryInfo Directory
{
get
{
return new DirectoryInfo(Path.GetDirectoryName(this.FullName));
}
}
/// <summary>
/// Gets the full path of the directory that contains the archive.
/// </summary>
/// <value>The full path of the directory that contains the archive.</value>
public string DirectoryName
{
get
{
return Path.GetDirectoryName(this.FullName);
}
}
/// <summary>
/// Gets the size of the archive.
/// </summary>
/// <value>The size of the archive in bytes.</value>
public long Length
{
get
{
return new FileInfo(this.FullName).Length;
}
}
/// <summary>
/// Gets the file name of the archive.
/// </summary>
/// <value>The file name of the archive, not including any path.</value>
public override string Name
{
get
{
return Path.GetFileName(this.FullName);
}
}
/// <summary>
/// Checks if the archive exists.
/// </summary>
/// <value>True if the archive exists; else false.</value>
public override bool Exists
{
get
{
return File.Exists(this.FullName);
}
}
/// <summary>
/// Gets the full path of the archive.
/// </summary>
/// <returns>The full path of the archive.</returns>
public override string ToString()
{
return this.FullName;
}
/// <summary>
/// Deletes the archive.
/// </summary>
public override void Delete()
{
File.Delete(this.FullName);
}
/// <summary>
/// Copies an existing archive to another location.
/// </summary>
/// <param name="destFileName">The destination file path.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void CopyTo(string destFileName)
{
File.Copy(this.FullName, destFileName);
}
/// <summary>
/// Copies an existing archive to another location, optionally
/// overwriting the destination file.
/// </summary>
/// <param name="destFileName">The destination file path.</param>
/// <param name="overwrite">If true, the destination file will be
/// overwritten if it exists.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void CopyTo(string destFileName, bool overwrite)
{
File.Copy(this.FullName, destFileName, overwrite);
}
/// <summary>
/// Moves an existing archive to another location.
/// </summary>
/// <param name="destFileName">The destination file path.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void MoveTo(string destFileName)
{
File.Move(this.FullName, destFileName);
this.FullPath = Path.GetFullPath(destFileName);
}
/// <summary>
/// Checks if the archive contains a valid archive header.
/// </summary>
/// <returns>True if the file is a valid archive; false otherwise.</returns>
public bool IsValid()
{
using (Stream stream = File.OpenRead(this.FullName))
{
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
return compressionEngine.FindArchiveOffset(stream) >= 0;
}
}
}
/// <summary>
/// Gets information about the files contained in the archive.
/// </summary>
/// <returns>A list of <see cref="ArchiveFileInfo"/> objects, each
/// containing information about a file in the archive.</returns>
public IList<ArchiveFileInfo> GetFiles()
{
return this.InternalGetFiles((Predicate<string>) null);
}
/// <summary>
/// Gets information about the certain files contained in the archive file.
/// </summary>
/// <param name="searchPattern">The search string, such as
/// &quot;*.txt&quot;.</param>
/// <returns>A list of <see cref="ArchiveFileInfo"/> objects, each containing
/// information about a file in the archive.</returns>
public IList<ArchiveFileInfo> GetFiles(string searchPattern)
{
if (searchPattern == null)
{
throw new ArgumentNullException("searchPattern");
}
string regexPattern = String.Format(
CultureInfo.InvariantCulture,
"^{0}$",
Regex.Escape(searchPattern).Replace("\\*", ".*").Replace("\\?", "."));
Regex regex = new Regex(
regexPattern,
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
return this.InternalGetFiles(
delegate(string match)
{
return regex.IsMatch(match);
});
}
/// <summary>
/// Extracts all files from an archive to a destination directory.
/// </summary>
/// <param name="destDirectory">Directory where the files are to be
/// extracted.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void Unpack(string destDirectory)
{
this.Unpack(destDirectory, null);
}
/// <summary>
/// Extracts all files from an archive to a destination directory,
/// optionally extracting only newer files.
/// </summary>
/// <param name="destDirectory">Directory where the files are to be
/// extracted.</param>
/// <param name="progressHandler">Handler for receiving progress
/// information; this may be null if progress is not desired.</param>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void Unpack(
string destDirectory,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
compressionEngine.Progress += progressHandler;
ArchiveFileStreamContext streamContext =
new ArchiveFileStreamContext(this.FullName, destDirectory, null);
streamContext.EnableOffsetOpen = true;
compressionEngine.Unpack(streamContext, null);
}
}
/// <summary>
/// Extracts a single file from the archive.
/// </summary>
/// <param name="fileName">The name of the file in the archive. Also
/// includes the internal path of the file, if any. File name matching
/// is case-insensitive.</param>
/// <param name="destFileName">The path where the file is to be
/// extracted on disk.</param>
/// <remarks>If <paramref name="destFileName"/> already exists,
/// it will be overwritten.</remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void UnpackFile(string fileName, string destFileName)
{
if (fileName == null)
{
throw new ArgumentNullException("fileName");
}
if (destFileName == null)
{
throw new ArgumentNullException("destFileName");
}
this.UnpackFiles(
new string[] { fileName },
null,
new string[] { destFileName });
}
/// <summary>
/// Extracts multiple files from the archive.
/// </summary>
/// <param name="fileNames">The names of the files in the archive.
/// Each name includes the internal path of the file, if any. File name
/// matching is case-insensitive.</param>
/// <param name="destDirectory">This parameter may be null, but if
/// specified it is the root directory for any relative paths in
/// <paramref name="destFileNames"/>.</param>
/// <param name="destFileNames">The paths where the files are to be
/// extracted on disk. If this parameter is null, the files will be
/// extracted with the names from the archive.</param>
/// <remarks>
/// If any extracted files already exist on disk, they will be overwritten.
/// <p>The <paramref name="destDirectory"/> and
/// <paramref name="destFileNames"/> parameters cannot both be null.</p>
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void UnpackFiles(
IList<string> fileNames,
string destDirectory,
IList<string> destFileNames)
{
this.UnpackFiles(fileNames, destDirectory, destFileNames, null);
}
/// <summary>
/// Extracts multiple files from the archive, optionally extracting
/// only newer files.
/// </summary>
/// <param name="fileNames">The names of the files in the archive.
/// Each name includes the internal path of the file, if any. File name
/// matching is case-insensitive.</param>
/// <param name="destDirectory">This parameter may be null, but if
/// specified it is the root directory for any relative paths in
/// <paramref name="destFileNames"/>.</param>
/// <param name="destFileNames">The paths where the files are to be
/// extracted on disk. If this parameter is null, the files will be
/// extracted with the names from the archive.</param>
/// <param name="progressHandler">Handler for receiving progress information;
/// this may be null if progress is not desired.</param>
/// <remarks>
/// If any extracted files already exist on disk, they will be overwritten.
/// <p>The <paramref name="destDirectory"/> and
/// <paramref name="destFileNames"/> parameters cannot both be null.</p>
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void UnpackFiles(
IList<string> fileNames,
string destDirectory,
IList<string> destFileNames,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
if (fileNames == null)
{
throw new ArgumentNullException("fileNames");
}
if (destFileNames == null)
{
if (destDirectory == null)
{
throw new ArgumentNullException("destFileNames");
}
destFileNames = fileNames;
}
if (destFileNames.Count != fileNames.Count)
{
throw new ArgumentOutOfRangeException("destFileNames");
}
IDictionary<string, string> files =
ArchiveInfo.CreateStringDictionary(fileNames, destFileNames);
this.UnpackFileSet(files, destDirectory, progressHandler);
}
/// <summary>
/// Extracts multiple files from the archive.
/// </summary>
/// <param name="fileNames">A mapping from internal file paths to
/// external file paths. Case-senstivity when matching internal paths
/// depends on the IDictionary implementation.</param>
/// <param name="destDirectory">This parameter may be null, but if
/// specified it is the root directory for any relative external paths
/// in <paramref name="fileNames"/>.</param>
/// <remarks>
/// If any extracted files already exist on disk, they will be overwritten.
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void UnpackFileSet(
IDictionary<string, string> fileNames,
string destDirectory)
{
this.UnpackFileSet(fileNames, destDirectory, null);
}
/// <summary>
/// Extracts multiple files from the archive.
/// </summary>
/// <param name="fileNames">A mapping from internal file paths to
/// external file paths. Case-senstivity when matching internal
/// paths depends on the IDictionary implementation.</param>
/// <param name="destDirectory">This parameter may be null, but if
/// specified it is the root directory for any relative external
/// paths in <paramref name="fileNames"/>.</param>
/// <param name="progressHandler">Handler for receiving progress
/// information; this may be null if progress is not desired.</param>
/// <remarks>
/// If any extracted files already exist on disk, they will be overwritten.
/// </remarks>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
public void UnpackFileSet(
IDictionary<string, string> fileNames,
string destDirectory,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
if (fileNames == null)
{
throw new ArgumentNullException("fileNames");
}
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
compressionEngine.Progress += progressHandler;
ArchiveFileStreamContext streamContext =
new ArchiveFileStreamContext(this.FullName, destDirectory, fileNames);
streamContext.EnableOffsetOpen = true;
compressionEngine.Unpack(
streamContext,
delegate(string match)
{
return fileNames.ContainsKey(match);
});
}
}
/// <summary>
/// Opens a file inside the archive for reading without actually
/// extracting the file to disk.
/// </summary>
/// <param name="fileName">The name of the file in the archive. Also
/// includes the internal path of the file, if any. File name matching
/// is case-insensitive.</param>
/// <returns>
/// A stream for reading directly from the packed file. Like any stream
/// this should be closed/disposed as soon as it is no longer needed.
/// </returns>
public Stream OpenRead(string fileName)
{
Stream archiveStream = File.OpenRead(this.FullName);
CompressionEngine compressionEngine = this.CreateCompressionEngine();
Stream fileStream = compressionEngine.Unpack(archiveStream, fileName);
// Attach the archiveStream and compressionEngine to the
// fileStream so they get disposed when the fileStream is disposed.
return new CargoStream(fileStream, archiveStream, compressionEngine);
}
/// <summary>
/// Opens a file inside the archive for reading text with UTF-8 encoding
/// without actually extracting the file to disk.
/// </summary>
/// <param name="fileName">The name of the file in the archive. Also
/// includes the internal path of the file, if any. File name matching
/// is case-insensitive.</param>
/// <returns>
/// A reader for reading text directly from the packed file. Like any reader
/// this should be closed/disposed as soon as it is no longer needed.
/// </returns>
/// <remarks>
/// To open an archived text file with different encoding, use the
/// <see cref="OpenRead" /> method and pass the returned stream to one of
/// the <see cref="StreamReader" /> constructor overloads.
/// </remarks>
public StreamReader OpenText(string fileName)
{
return new StreamReader(this.OpenRead(fileName));
}
/// <summary>
/// Compresses all files in a directory into the archive.
/// Does not include subdirectories.
/// </summary>
/// <param name="sourceDirectory">The directory containing the
/// files to be included.</param>
/// <remarks>
/// Uses maximum compression level.
/// </remarks>
public void Pack(string sourceDirectory)
{
this.Pack(sourceDirectory, false, CompressionLevel.Max, null);
}
/// <summary>
/// Compresses all files in a directory into the archive, optionally
/// including subdirectories.
/// </summary>
/// <param name="sourceDirectory">This is the root directory
/// for to pack all files.</param>
/// <param name="includeSubdirectories">If true, recursively include
/// files in subdirectories.</param>
/// <param name="compLevel">The compression level used when creating
/// the archive.</param>
/// <param name="progressHandler">Handler for receiving progress information;
/// this may be null if progress is not desired.</param>
/// <remarks>
/// The files are stored in the archive using their relative file paths in
/// the directory tree, if supported by the archive file format.
/// </remarks>
public void Pack(
string sourceDirectory,
bool includeSubdirectories,
CompressionLevel compLevel,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
IList<string> files = this.GetRelativeFilePathsInDirectoryTree(
sourceDirectory, includeSubdirectories);
this.PackFiles(sourceDirectory, files, files, compLevel, progressHandler);
}
/// <summary>
/// Compresses files into the archive, specifying the names used to
/// store the files in the archive.
/// </summary>
/// <param name="sourceDirectory">This parameter may be null, but
/// if specified it is the root directory
/// for any relative paths in <paramref name="sourceFileNames"/>.</param>
/// <param name="sourceFileNames">The list of files to be included in
/// the archive.</param>
/// <param name="fileNames">The names of the files as they are stored
/// in the archive. Each name
/// includes the internal path of the file, if any. This parameter may
/// be null, in which case the files are stored in the archive with their
/// source file names and no path information.</param>
/// <remarks>
/// Uses maximum compression level.
/// <p>Duplicate items in the <paramref name="fileNames"/> array will cause
/// an <see cref="ArchiveException"/>.</p>
/// </remarks>
public void PackFiles(
string sourceDirectory,
IList<string> sourceFileNames,
IList<string> fileNames)
{
this.PackFiles(
sourceDirectory,
sourceFileNames,
fileNames,
CompressionLevel.Max,
null);
}
/// <summary>
/// Compresses files into the archive, specifying the names used to
/// store the files in the archive.
/// </summary>
/// <param name="sourceDirectory">This parameter may be null, but if
/// specified it is the root directory
/// for any relative paths in <paramref name="sourceFileNames"/>.</param>
/// <param name="sourceFileNames">The list of files to be included in
/// the archive.</param>
/// <param name="fileNames">The names of the files as they are stored in
/// the archive. Each name includes the internal path of the file, if any.
/// This parameter may be null, in which case the files are stored in the
/// archive with their source file names and no path information.</param>
/// <param name="compLevel">The compression level used when creating the
/// archive.</param>
/// <param name="progressHandler">Handler for receiving progress information;
/// this may be null if progress is not desired.</param>
/// <remarks>
/// Duplicate items in the <paramref name="fileNames"/> array will cause
/// an <see cref="ArchiveException"/>.
/// </remarks>
public void PackFiles(
string sourceDirectory,
IList<string> sourceFileNames,
IList<string> fileNames,
CompressionLevel compLevel,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
if (sourceFileNames == null)
{
throw new ArgumentNullException("sourceFileNames");
}
if (fileNames == null)
{
string[] fileNamesArray = new string[sourceFileNames.Count];
for (int i = 0; i < sourceFileNames.Count; i++)
{
fileNamesArray[i] = Path.GetFileName(sourceFileNames[i]);
}
fileNames = fileNamesArray;
}
else if (fileNames.Count != sourceFileNames.Count)
{
throw new ArgumentOutOfRangeException("fileNames");
}
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
compressionEngine.Progress += progressHandler;
IDictionary<string, string> contextFiles =
ArchiveInfo.CreateStringDictionary(fileNames, sourceFileNames);
ArchiveFileStreamContext streamContext = new ArchiveFileStreamContext(
this.FullName, sourceDirectory, contextFiles);
streamContext.EnableOffsetOpen = true;
compressionEngine.CompressionLevel = compLevel;
compressionEngine.Pack(streamContext, fileNames);
}
}
/// <summary>
/// Compresses files into the archive, specifying the names used
/// to store the files in the archive.
/// </summary>
/// <param name="sourceDirectory">This parameter may be null, but if
/// specified it is the root directory
/// for any relative paths in <paramref name="fileNames"/>.</param>
/// <param name="fileNames">A mapping from internal file paths to
/// external file paths.</param>
/// <remarks>
/// Uses maximum compression level.
/// </remarks>
public void PackFileSet(
string sourceDirectory,
IDictionary<string, string> fileNames)
{
this.PackFileSet(sourceDirectory, fileNames, CompressionLevel.Max, null);
}
/// <summary>
/// Compresses files into the archive, specifying the names used to
/// store the files in the archive.
/// </summary>
/// <param name="sourceDirectory">This parameter may be null, but if
/// specified it is the root directory
/// for any relative paths in <paramref name="fileNames"/>.</param>
/// <param name="fileNames">A mapping from internal file paths to
/// external file paths.</param>
/// <param name="compLevel">The compression level used when creating
/// the archive.</param>
/// <param name="progressHandler">Handler for receiving progress information;
/// this may be null if progress is not desired.</param>
public void PackFileSet(
string sourceDirectory,
IDictionary<string, string> fileNames,
CompressionLevel compLevel,
EventHandler<ArchiveProgressEventArgs> progressHandler)
{
if (fileNames == null)
{
throw new ArgumentNullException("fileNames");
}
string[] fileNamesArray = new string[fileNames.Count];
fileNames.Keys.CopyTo(fileNamesArray, 0);
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
compressionEngine.Progress += progressHandler;
ArchiveFileStreamContext streamContext = new ArchiveFileStreamContext(
this.FullName, sourceDirectory, fileNames);
streamContext.EnableOffsetOpen = true;
compressionEngine.CompressionLevel = compLevel;
compressionEngine.Pack(streamContext, fileNamesArray);
}
}
/// <summary>
/// Given a directory, gets the relative paths of all files in the
/// directory, optionally including all subdirectories.
/// </summary>
/// <param name="dir">The directory to search.</param>
/// <param name="includeSubdirectories">True to include subdirectories
/// in the search.</param>
/// <returns>A list of file paths relative to the directory.</returns>
internal IList<string> GetRelativeFilePathsInDirectoryTree(
string dir, bool includeSubdirectories)
{
IList<string> fileList = new List<string>();
this.RecursiveGetRelativeFilePathsInDirectoryTree(
dir, String.Empty, includeSubdirectories, fileList);
return fileList;
}
/// <summary>
/// Retrieves information about one file from this archive.
/// </summary>
/// <param name="path">Path of the file in the archive.</param>
/// <returns>File information, or null if the file was not found
/// in the archive.</returns>
internal ArchiveFileInfo GetFile(string path)
{
IList<ArchiveFileInfo> files = this.InternalGetFiles(
delegate(string match)
{
return String.Compare(
match, path, true, CultureInfo.InvariantCulture) == 0;
});
return (files != null && files.Count > 0 ? files[0] : null);
}
/// <summary>
/// Creates a compression engine that does the low-level work for
/// this object.
/// </summary>
/// <returns>A new compression engine instance that matches the specific
/// subclass of archive.</returns>
/// <remarks>
/// Each instance will be <see cref="CompressionEngine.Dispose()"/>d
/// immediately after use.
/// </remarks>
protected abstract CompressionEngine CreateCompressionEngine();
/// <summary>
/// Creates a case-insensitive dictionary mapping from one list of
/// strings to the other.
/// </summary>
/// <param name="keys">List of keys.</param>
/// <param name="values">List of values that are mapped 1-to-1 to
/// the keys.</param>
/// <returns>A filled dictionary of the strings.</returns>
private static IDictionary<string, string> CreateStringDictionary(
IList<string> keys, IList<string> values)
{
IDictionary<string, string> stringDict =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < keys.Count; i++)
{
stringDict.Add(keys[i], values[i]);
}
return stringDict;
}
/// <summary>
/// Recursive-descent helper function for
/// GetRelativeFilePathsInDirectoryTree.
/// </summary>
/// <param name="dir">The root directory of the search.</param>
/// <param name="relativeDir">The relative directory to be
/// processed now.</param>
/// <param name="includeSubdirectories">True to descend into
/// subdirectories.</param>
/// <param name="fileList">List of files found so far.</param>
private void RecursiveGetRelativeFilePathsInDirectoryTree(
string dir,
string relativeDir,
bool includeSubdirectories,
IList<string> fileList)
{
foreach (string file in System.IO.Directory.GetFiles(dir))
{
string fileName = Path.GetFileName(file);
fileList.Add(Path.Combine(relativeDir, fileName));
}
if (includeSubdirectories)
{
foreach (string subDir in System.IO.Directory.GetDirectories(dir))
{
string subDirName = Path.GetFileName(subDir);
this.RecursiveGetRelativeFilePathsInDirectoryTree(
Path.Combine(dir, subDirName),
Path.Combine(relativeDir, subDirName),
includeSubdirectories,
fileList);
}
}
}
/// <summary>
/// Uses a CompressionEngine to get ArchiveFileInfo objects from this
/// archive, and then associates them with this ArchiveInfo instance.
/// </summary>
/// <param name="fileFilter">Optional predicate that can determine
/// which files to process.</param>
/// <returns>A list of <see cref="ArchiveFileInfo"/> objects, each
/// containing information about a file in the archive.</returns>
private IList<ArchiveFileInfo> InternalGetFiles(Predicate<string> fileFilter)
{
using (CompressionEngine compressionEngine = this.CreateCompressionEngine())
{
ArchiveFileStreamContext streamContext =
new ArchiveFileStreamContext(this.FullName, null, null);
streamContext.EnableOffsetOpen = true;
IList<ArchiveFileInfo> files =
compressionEngine.GetFileInfo(streamContext, fileFilter);
for (int i = 0; i < files.Count; i++)
{
files[i].Archive = this;
}
return files;
}
}
}
}

Просмотреть файл

@ -0,0 +1,317 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveProgressEventArgs.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// Contains the data reported in an archive progress event.
/// </summary>
public class ArchiveProgressEventArgs : EventArgs
{
private ArchiveProgressType progressType;
private string currentFileName;
private int currentFileNumber;
private int totalFiles;
private long currentFileBytesProcessed;
private long currentFileTotalBytes;
private string currentArchiveName;
private short currentArchiveNumber;
private short totalArchives;
private long currentArchiveBytesProcessed;
private long currentArchiveTotalBytes;
private long fileBytesProcessed;
private long totalFileBytes;
/// <summary>
/// Creates a new ArchiveProgressEventArgs object from specified event parameters.
/// </summary>
/// <param name="progressType">type of status message</param>
/// <param name="currentFileName">name of the file being processed</param>
/// <param name="currentFileNumber">number of the current file being processed</param>
/// <param name="totalFiles">total number of files to be processed</param>
/// <param name="currentFileBytesProcessed">number of bytes processed so far when compressing or extracting a file</param>
/// <param name="currentFileTotalBytes">total number of bytes in the current file</param>
/// <param name="currentArchiveName">name of the current Archive</param>
/// <param name="currentArchiveNumber">current Archive number, when processing a chained set of Archives</param>
/// <param name="totalArchives">total number of Archives in a chained set</param>
/// <param name="currentArchiveBytesProcessed">number of compressed bytes processed so far during an extraction</param>
/// <param name="currentArchiveTotalBytes">total number of compressed bytes to be processed during an extraction</param>
/// <param name="fileBytesProcessed">number of uncompressed file bytes processed so far</param>
/// <param name="totalFileBytes">total number of uncompressed file bytes to be processed</param>
public ArchiveProgressEventArgs(
ArchiveProgressType progressType,
string currentFileName,
int currentFileNumber,
int totalFiles,
long currentFileBytesProcessed,
long currentFileTotalBytes,
string currentArchiveName,
int currentArchiveNumber,
int totalArchives,
long currentArchiveBytesProcessed,
long currentArchiveTotalBytes,
long fileBytesProcessed,
long totalFileBytes)
{
this.progressType = progressType;
this.currentFileName = currentFileName;
this.currentFileNumber = currentFileNumber;
this.totalFiles = totalFiles;
this.currentFileBytesProcessed = currentFileBytesProcessed;
this.currentFileTotalBytes = currentFileTotalBytes;
this.currentArchiveName = currentArchiveName;
this.currentArchiveNumber = (short) currentArchiveNumber;
this.totalArchives = (short) totalArchives;
this.currentArchiveBytesProcessed = currentArchiveBytesProcessed;
this.currentArchiveTotalBytes = currentArchiveTotalBytes;
this.fileBytesProcessed = fileBytesProcessed;
this.totalFileBytes = totalFileBytes;
}
/// <summary>
/// Gets the type of status message.
/// </summary>
/// <value>A <see cref="ArchiveProgressType"/> value indicating what type of progress event occurred.</value>
/// <remarks>
/// The handler may choose to ignore some types of progress events.
/// For example, if the handler will only list each file as it is
/// compressed/extracted, it can ignore events that
/// are not of type <see cref="ArchiveProgressType.FinishFile"/>.
/// </remarks>
public ArchiveProgressType ProgressType
{
get
{
return this.progressType;
}
}
/// <summary>
/// Gets the name of the file being processed. (The name of the file within the Archive; not the external
/// file path.) Also includes the internal path of the file, if any. Valid for
/// <see cref="ArchiveProgressType.StartFile"/>, <see cref="ArchiveProgressType.PartialFile"/>,
/// and <see cref="ArchiveProgressType.FinishFile"/> messages.
/// </summary>
/// <value>The name of the file currently being processed, or null if processing
/// is currently at the stream or archive level.</value>
public string CurrentFileName
{
get
{
return this.currentFileName;
}
}
/// <summary>
/// Gets the number of the current file being processed. The first file is number 0, and the last file
/// is <see cref="TotalFiles"/>-1. Valid for <see cref="ArchiveProgressType.StartFile"/>,
/// <see cref="ArchiveProgressType.PartialFile"/>, and <see cref="ArchiveProgressType.FinishFile"/> messages.
/// </summary>
/// <value>The number of the file currently being processed, or the most recent
/// file processed if processing is currently at the stream or archive level.</value>
public int CurrentFileNumber
{
get
{
return this.currentFileNumber;
}
}
/// <summary>
/// Gets the total number of files to be processed. Valid for all message types.
/// </summary>
/// <value>The total number of files to be processed that are known so far.</value>
public int TotalFiles
{
get
{
return this.totalFiles;
}
}
/// <summary>
/// Gets the number of bytes processed so far when compressing or extracting a file. Valid for
/// <see cref="ArchiveProgressType.StartFile"/>, <see cref="ArchiveProgressType.PartialFile"/>,
/// and <see cref="ArchiveProgressType.FinishFile"/> messages.
/// </summary>
/// <value>The number of uncompressed bytes processed so far for the current file,
/// or 0 if processing is currently at the stream or archive level.</value>
public long CurrentFileBytesProcessed
{
get
{
return this.currentFileBytesProcessed;
}
}
/// <summary>
/// Gets the total number of bytes in the current file. Valid for <see cref="ArchiveProgressType.StartFile"/>,
/// <see cref="ArchiveProgressType.PartialFile"/>, and <see cref="ArchiveProgressType.FinishFile"/> messages.
/// </summary>
/// <value>The uncompressed size of the current file being processed,
/// or 0 if processing is currently at the stream or archive level.</value>
public long CurrentFileTotalBytes
{
get
{
return this.currentFileTotalBytes;
}
}
/// <summary>
/// Gets the name of the current archive. Not necessarily the name of the archive on disk.
/// Valid for all message types.
/// </summary>
/// <value>The name of the current archive, or an empty string if no name was specified.</value>
public string CurrentArchiveName
{
get
{
return this.currentArchiveName;
}
}
/// <summary>
/// Gets the current archive number, when processing a chained set of archives. Valid for all message types.
/// </summary>
/// <value>The number of the current archive.</value>
/// <remarks>The first archive is number 0, and the last archive is
/// <see cref="TotalArchives"/>-1.</remarks>
public int CurrentArchiveNumber
{
get
{
return this.currentArchiveNumber;
}
}
/// <summary>
/// Gets the total number of known archives in a chained set. Valid for all message types.
/// </summary>
/// <value>The total number of known archives in a chained set.</value>
/// <remarks>
/// When using the compression option to auto-split into multiple archives based on data size,
/// this value will not be accurate until the end.
/// </remarks>
public int TotalArchives
{
get
{
return this.totalArchives;
}
}
/// <summary>
/// Gets the number of compressed bytes processed so far during extraction
/// of the current archive. Valid for all extraction messages.
/// </summary>
/// <value>The number of compressed bytes processed so far during extraction
/// of the current archive.</value>
public long CurrentArchiveBytesProcessed
{
get
{
return this.currentArchiveBytesProcessed;
}
}
/// <summary>
/// Gets the total number of compressed bytes to be processed during extraction
/// of the current archive. Valid for all extraction messages.
/// </summary>
/// <value>The total number of compressed bytes to be processed during extraction
/// of the current archive.</value>
public long CurrentArchiveTotalBytes
{
get
{
return this.currentArchiveTotalBytes;
}
}
/// <summary>
/// Gets the number of uncompressed bytes processed so far among all files. Valid for all message types.
/// </summary>
/// <value>The number of uncompressed file bytes processed so far among all files.</value>
/// <remarks>
/// When compared to <see cref="TotalFileBytes"/>, this can be used as a measure of overall progress.
/// </remarks>
public long FileBytesProcessed
{
get
{
return this.fileBytesProcessed;
}
}
/// <summary>
/// Gets the total number of uncompressed file bytes to be processed. Valid for all message types.
/// </summary>
/// <value>The total number of uncompressed bytes to be processed among all files.</value>
public long TotalFileBytes
{
get
{
return this.totalFileBytes;
}
}
#if DEBUG
/// <summary>
/// Creates a string representation of the progress event.
/// </summary>
/// <returns>a listing of all event parameters and values</returns>
public override string ToString()
{
string formatString =
"{0}\n" +
"\t CurrentFileName = {1}\n" +
"\t CurrentFileNumber = {2}\n" +
"\t TotalFiles = {3}\n" +
"\t CurrentFileBytesProcessed = {4}\n" +
"\t CurrentFileTotalBytes = {5}\n" +
"\t CurrentArchiveName = {6}\n" +
"\t CurrentArchiveNumber = {7}\n" +
"\t TotalArchives = {8}\n" +
"\t CurrentArchiveBytesProcessed = {9}\n" +
"\t CurrentArchiveTotalBytes = {10}\n" +
"\t FileBytesProcessed = {11}\n" +
"\t TotalFileBytes = {12}\n";
return String.Format(
System.Globalization.CultureInfo.InvariantCulture,
formatString,
this.ProgressType,
this.CurrentFileName,
this.CurrentFileNumber,
this.TotalFiles,
this.CurrentFileBytesProcessed,
this.CurrentFileTotalBytes,
this.CurrentArchiveName,
this.CurrentArchiveNumber,
this.TotalArchives,
this.CurrentArchiveBytesProcessed,
this.CurrentArchiveTotalBytes,
this.FileBytesProcessed,
this.TotalFileBytes);
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,79 @@
//---------------------------------------------------------------------
// <copyright file="ArchiveProgressType.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// The type of progress event.
/// </summary>
/// <remarks>
/// <p>PACKING EXAMPLE: The following sequence of events might be received when
/// extracting a simple archive file with 2 files.</p>
/// <list type="table">
/// <listheader><term>Message Type</term><description>Description</description></listheader>
/// <item><term>StartArchive</term> <description>Begin extracting archive</description></item>
/// <item><term>StartFile</term> <description>Begin extracting first file</description></item>
/// <item><term>PartialFile</term> <description>Extracting first file</description></item>
/// <item><term>PartialFile</term> <description>Extracting first file</description></item>
/// <item><term>FinishFile</term> <description>Finished extracting first file</description></item>
/// <item><term>StartFile</term> <description>Begin extracting second file</description></item>
/// <item><term>PartialFile</term> <description>Extracting second file</description></item>
/// <item><term>FinishFile</term> <description>Finished extracting second file</description></item>
/// <item><term>FinishArchive</term><description>Finished extracting archive</description></item>
/// </list>
/// <p></p>
/// <p>UNPACKING EXAMPLE: Packing 3 files into 2 archive chunks, where the second file is
/// continued to the second archive chunk.</p>
/// <list type="table">
/// <listheader><term>Message Type</term><description>Description</description></listheader>
/// <item><term>StartFile</term> <description>Begin compressing first file</description></item>
/// <item><term>FinishFile</term> <description>Finished compressing first file</description></item>
/// <item><term>StartFile</term> <description>Begin compressing second file</description></item>
/// <item><term>PartialFile</term> <description>Compressing second file</description></item>
/// <item><term>PartialFile</term> <description>Compressing second file</description></item>
/// <item><term>FinishFile</term> <description>Finished compressing second file</description></item>
/// <item><term>StartArchive</term> <description>Begin writing first archive</description></item>
/// <item><term>PartialArchive</term><description>Writing first archive</description></item>
/// <item><term>FinishArchive</term> <description>Finished writing first archive</description></item>
/// <item><term>StartFile</term> <description>Begin compressing third file</description></item>
/// <item><term>PartialFile</term> <description>Compressing third file</description></item>
/// <item><term>FinishFile</term> <description>Finished compressing third file</description></item>
/// <item><term>StartArchive</term> <description>Begin writing second archive</description></item>
/// <item><term>PartialArchive</term><description>Writing second archive</description></item>
/// <item><term>FinishArchive</term> <description>Finished writing second archive</description></item>
/// </list>
/// </remarks>
public enum ArchiveProgressType : int
{
/// <summary>Status message before beginning the packing or unpacking an individual file.</summary>
StartFile,
/// <summary>Status message (possibly reported multiple times) during the process of packing or unpacking a file.</summary>
PartialFile,
/// <summary>Status message after completion of the packing or unpacking an individual file.</summary>
FinishFile,
/// <summary>Status message before beginning the packing or unpacking an archive.</summary>
StartArchive,
/// <summary>Status message (possibly reported multiple times) during the process of packing or unpacking an archiv.</summary>
PartialArchive,
/// <summary>Status message after completion of the packing or unpacking of an archive.</summary>
FinishArchive,
}
}

Просмотреть файл

@ -0,0 +1,30 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyDescription("Abstract base libraries for archive packing and unpacking")]
[assembly: CLSCompliant(true)]
[assembly: ComVisible(false)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Unrestricted = true)]
// SECURITY: Review carefully!
// This assembly is designed so that partially trusted callers should be able to
// do compression and extraction in a file path where they have limited
// file I/O permission. Or they can even do in-memory compression and extraction
// with absolutely no file I/O permission.
[assembly: AllowPartiallyTrustedCallers]

Просмотреть файл

@ -0,0 +1,100 @@
//---------------------------------------------------------------------
// <copyright file="BasicUnpackStreamContext.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Stream context used to extract a single file from an archive into a memory stream.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")]
public class BasicUnpackStreamContext : IUnpackStreamContext
{
private Stream archiveStream;
private Stream fileStream;
/// <summary>
/// Creates a new BasicExtractStreamContext that reads from the specified archive stream.
/// </summary>
/// <param name="archiveStream">Archive stream to read from.</param>
public BasicUnpackStreamContext(Stream archiveStream)
{
this.archiveStream = archiveStream;
}
/// <summary>
/// Gets the stream for the extracted file, or null if no file was extracted.
/// </summary>
public Stream FileStream
{
get
{
return this.fileStream;
}
}
/// <summary>
/// Opens the archive stream for reading. Returns a DuplicateStream instance,
/// so the stream may be virtually opened multiple times.
/// </summary>
/// <param name="archiveNumber">The archive number to open (ignored; 0 is assumed).</param>
/// <param name="archiveName">The name of the archive being opened.</param>
/// <param name="compressionEngine">Instance of the compression engine doing the operations.</param>
/// <returns>A stream from which archive bytes are read.</returns>
public Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine)
{
return new DuplicateStream(this.archiveStream);
}
/// <summary>
/// Does *not* close the stream. The archive stream should be managed by
/// the code that invokes the archive extraction.
/// </summary>
/// <param name="archiveNumber">The archive number of the stream to close.</param>
/// <param name="archiveName">The name of the archive being closed.</param>
/// <param name="stream">The stream being closed.</param>
public void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream)
{
// Do nothing.
}
/// <summary>
/// Opens a stream for writing extracted file bytes. The returned stream is a MemoryStream
/// instance, so the file is extracted straight into memory.
/// </summary>
/// <param name="path">Path of the file within the archive.</param>
/// <param name="fileSize">The uncompressed size of the file to be extracted.</param>
/// <param name="lastWriteTime">The last write time of the file.</param>
/// <returns>A stream where extracted file bytes are to be written.</returns>
public Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime)
{
this.fileStream = new MemoryStream(new byte[fileSize], 0, (int) fileSize, true, true);
return this.fileStream;
}
/// <summary>
/// Does *not* close the file stream. The file stream is saved in memory so it can
/// be read later.
/// </summary>
/// <param name="path">Path of the file within the archive.</param>
/// <param name="stream">The file stream to be closed.</param>
/// <param name="attributes">The attributes of the extracted file.</param>
/// <param name="lastWriteTime">The last write time of the file.</param>
public void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime)
{
// Do nothing.
}
}
}

Просмотреть файл

@ -0,0 +1,202 @@
//---------------------------------------------------------------------
// <copyright file="CargoStream.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// Wraps a source stream and carries additional items that are disposed when the stream is closed.
/// </summary>
public class CargoStream : Stream
{
private Stream source;
private List<IDisposable> cargo;
/// <summary>
/// Creates a new a cargo stream.
/// </summary>
/// <param name="source">source of the stream</param>
/// <param name="cargo">List of additional items that are disposed when the stream is closed.
/// The order of the list is the order in which the items are disposed.</param>
public CargoStream(Stream source, params IDisposable[] cargo)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
this.source = source;
this.cargo = new List<IDisposable>(cargo);
}
/// <summary>
/// Gets the source stream of the cargo stream.
/// </summary>
public Stream Source
{
get
{
return this.source;
}
}
/// <summary>
/// Gets the list of additional items that are disposed when the stream is closed.
/// The order of the list is the order in which the items are disposed. The contents can be modified any time.
/// </summary>
public IList<IDisposable> Cargo
{
get
{
return this.cargo;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports reading.
/// </summary>
/// <value>true if the stream supports reading; otherwise, false.</value>
public override bool CanRead
{
get
{
return this.source.CanRead;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports writing.
/// </summary>
/// <value>true if the stream supports writing; otherwise, false.</value>
public override bool CanWrite
{
get
{
return this.source.CanWrite;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports seeking.
/// </summary>
/// <value>true if the stream supports seeking; otherwise, false.</value>
public override bool CanSeek
{
get
{
return this.source.CanSeek;
}
}
/// <summary>
/// Gets the length of the source stream.
/// </summary>
public override long Length
{
get
{
return this.source.Length;
}
}
/// <summary>
/// Gets or sets the position of the source stream.
/// </summary>
public override long Position
{
get
{
return this.source.Position;
}
set
{
this.source.Position = value;
}
}
/// <summary>
/// Flushes the source stream.
/// </summary>
public override void Flush()
{
this.source.Flush();
}
/// <summary>
/// Sets the length of the source stream.
/// </summary>
/// <param name="value">The desired length of the stream in bytes.</param>
public override void SetLength(long value)
{
this.source.SetLength(value);
}
/// <summary>
/// Closes the source stream and also closes the additional objects that are carried.
/// </summary>
public override void Close()
{
this.source.Close();
foreach (IDisposable cargoObject in this.cargo)
{
cargoObject.Dispose();
}
}
/// <summary>
/// Reads from the source stream.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer
/// contains the specified byte array with the values between offset and
/// (offset + count - 1) replaced by the bytes read from the source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin
/// storing the data read from the stream.</param>
/// <param name="count">The maximum number of bytes to be read from the stream.</param>
/// <returns>The total number of bytes read into the buffer. This can be less
/// than the number of bytes requested if that many bytes are not currently available,
/// or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
return this.source.Read(buffer, offset, count);
}
/// <summary>
/// Writes to the source stream.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count
/// bytes from buffer to the stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which
/// to begin copying bytes to the stream.</param>
/// <param name="count">The number of bytes to be written to the stream.</param>
public override void Write(byte[] buffer, int offset, int count)
{
this.source.Write(buffer, offset, count);
}
/// <summary>
/// Changes the position of the source stream.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type SeekOrigin indicating the reference
/// point used to obtain the new position.</param>
/// <returns>The new position within the stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
return this.source.Seek(offset, origin);
}
}
}

Просмотреть файл

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Comment CommentText="File-based classes">
<Position X="2.35" Y="1.442" Height="0.408" Width="0.783" />
</Comment>
<Comment CommentText="Stream-based classes">
<Position X="9.649" Y="1.317" Height="0.4" Width="0.996" />
</Comment>
<Class Name="Microsoft.Deployment.Compression.ArchiveException" Collapsed="true">
<Position X="3" Y="4.25" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>ArchiveException.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Microsoft.Deployment.Compression.ArchiveFileInfo">
<Position X="3" Y="0.5" Width="2" />
<Members>
<Method Name="ArchiveFileInfo" Hidden="true" />
<Field Name="archiveInfo" Hidden="true" />
<Field Name="archiveNumber" Hidden="true" />
<Field Name="attributes" Hidden="true" />
<Field Name="exists" Hidden="true" />
<Method Name="GetObjectData" Hidden="true" />
<Field Name="initialized" Hidden="true" />
<Field Name="lastWriteTime" Hidden="true" />
<Field Name="length" Hidden="true" />
<Field Name="name" Hidden="true" />
<Field Name="path" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AAAgAAAAIRJAAIMEAEACgARwAAEEEAAAASAAAAEAIAA=</HashCode>
<FileName>ArchiveFileInfo.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Microsoft.Deployment.Compression.ArchiveInfo">
<Position X="0.5" Y="0.5" Width="2.25" />
<Members>
<Method Name="ArchiveInfo" Hidden="true" />
<Method Name="CreateStringDictionary" Hidden="true" />
<Method Name="GetFile" Hidden="true" />
<Method Name="GetRelativeFilePathsInDirectoryTree" Hidden="true" />
<Method Name="InternalGetFiles" Hidden="true" />
<Method Name="RecursiveGetRelativeFilePathsInDirectoryTree" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AAEAABAAIAAAAgQEAAgBAARAHAEJACAAAABEAAkAMAI=</HashCode>
<FileName>ArchiveInfo.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Microsoft.Deployment.Compression.ArchiveFileStreamContext">
<Position X="12.75" Y="0.75" Width="2.25" />
<Members>
<Field Name="archiveFiles" Hidden="true" />
<Method Name="ArchiveFileStreamContext" Hidden="true" />
<Method Name="CloseArchiveReadStream" Hidden="true" />
<Method Name="CloseArchiveWriteStream" Hidden="true" />
<Method Name="CloseFileReadStream" Hidden="true" />
<Method Name="CloseFileWriteStream" Hidden="true" />
<Field Name="directory" Hidden="true" />
<Field Name="enableOffsetOpen" Hidden="true" />
<Field Name="extractOnlyNewerFiles" Hidden="true" />
<Field Name="files" Hidden="true" />
<Method Name="GetArchiveName" Hidden="true" />
<Method Name="GetOption" Hidden="true" />
<Method Name="OpenArchiveReadStream" Hidden="true" />
<Method Name="OpenArchiveWriteStream" Hidden="true" />
<Method Name="OpenFileReadStream" Hidden="true" />
<Method Name="OpenFileWriteStream" Hidden="true" />
<Method Name="TranslateFilePath" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AEQAABgAAACQAACACACAAgAQAAIgAAAAACAMgAAEAKA=</HashCode>
<FileName>ArchiveFileStreamContext.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="Microsoft.Deployment.Compression.ArchiveProgressEventArgs">
<Position X="5.25" Y="0.5" Width="2.25" />
<Members>
<Method Name="ArchiveProgressEventArgs" Hidden="true" />
<Field Name="currentArchiveBytesProcessed" Hidden="true" />
<Field Name="currentArchiveName" Hidden="true" />
<Field Name="currentArchiveNumber" Hidden="true" />
<Field Name="currentArchiveTotalBytes" Hidden="true" />
<Field Name="currentFileBytesProcessed" Hidden="true" />
<Field Name="currentFileName" Hidden="true" />
<Field Name="currentFileNumber" Hidden="true" />
<Field Name="currentFileTotalBytes" Hidden="true" />
<Field Name="fileBytesProcessed" Hidden="true" />
<Field Name="progressType" Hidden="true" />
<Field Name="totalArchives" Hidden="true" />
<Field Name="totalFileBytes" Hidden="true" />
<Field Name="totalFiles" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AAMCAQASACAAABBBAAASUAAAQBAAAMAAAAGQAAgBEAA=</HashCode>
<FileName>ArchiveProgressEventArgs.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Microsoft.Deployment.Compression.BasicUnpackStreamContext">
<Position X="12.75" Y="3" Width="2.25" />
<Members>
<Field Name="archiveStream" Hidden="true" />
<Method Name="BasicUnpackStreamContext" Hidden="true" />
<Method Name="CloseArchiveReadStream" Hidden="true" />
<Method Name="CloseFileWriteStream" Hidden="true" />
<Field Name="fileStream" Hidden="true" />
<Method Name="OpenArchiveReadStream" Hidden="true" />
<Method Name="OpenFileWriteStream" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AAAAAAgAAACEAAAAAAAAAAAAAAAgAAAAIAAMAAAAAAA=</HashCode>
<FileName>BasicUnpackStreamContext.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="Microsoft.Deployment.Compression.CompressionEngine">
<Position X="8" Y="0.5" Width="2.25" />
<Members>
<Method Name="~CompressionEngine" Hidden="true" />
<Method Name="CompressionEngine" Hidden="true" />
<Field Name="compressionLevel" Hidden="true" />
<Field Name="dontUseTempFiles" Hidden="true" />
</Members>
<TypeIdentifier>
<HashCode>AAAEAAAABCBAACRgAAAAAAQAAEAAAAAAQAEAAAiAAAI=</HashCode>
<FileName>CompressionEngine.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="Microsoft.Deployment.Compression.DuplicateStream" Collapsed="true">
<Position X="10.5" Y="4.25" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAEAAAgAAQAIgGAAAIABgAAAAAAAAAAAAAAGIACA=</HashCode>
<FileName>DuplicateStream.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="Microsoft.Deployment.Compression.OffsetStream" Collapsed="true">
<Position X="8" Y="4.25" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAAgAAQAIgGAAAAABgAAAAAEAgAAAAAAGIwCA=</HashCode>
<FileName>OffsetStream.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="Microsoft.Deployment.Compression.IPackStreamContext">
<Position X="10.5" Y="0.5" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAACAAACAAAAQAAAgAAAAACAIAAAAAAA=</HashCode>
<FileName>IPackStreamContext.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="Microsoft.Deployment.Compression.IUnpackStreamContext">
<Position X="10.5" Y="2.5" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAgAAACAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAA=</HashCode>
<FileName>IUnpackStreamContext.cs</FileName>
</TypeIdentifier>
</Interface>
<Enum Name="Microsoft.Deployment.Compression.ArchiveProgressType" Collapsed="true">
<Position X="5.25" Y="3.75" Width="2" />
<TypeIdentifier>
<HashCode>QAAAAAAAAAAAAIAAgAAAAAAAAAQAAAAACIAAAAAAAAA=</HashCode>
<FileName>ArchiveProgressType.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Microsoft.Deployment.Compression.CompressionLevel" Collapsed="true">
<Position X="5.25" Y="4.5" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAABAAAAAAEAAAAAAAAAAIAAAAAAAAAAEAAAA=</HashCode>
<FileName>CompressionLevel.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Verdana" Size="8" />
</ClassDiagram>

Просмотреть файл

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="Compression.csproj" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{2D62850C-9F81-4BE9-BDF3-9379389C8F7B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Deployment.Compression</RootNamespace>
<AssemblyName>Microsoft.Deployment.Compression</AssemblyName>
<CreateDocumentationFile>true</CreateDocumentationFile>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FxCopEnabled>false</FxCopEnabled>
</PropertyGroup>
<ItemGroup>
<Compile Include="ArchiveException.cs" />
<Compile Include="ArchiveFileInfo.cs" />
<Compile Include="ArchiveInfo.cs" />
<Compile Include="ArchiveProgressEventArgs.cs" />
<Compile Include="ArchiveProgressType.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="ArchiveFileStreamContext.cs" />
<Compile Include="BasicUnpackStreamContext.cs" />
<Compile Include="CompressionEngine.cs" />
<Compile Include="CompressionLevel.cs" />
<Compile Include="CargoStream.cs" />
<Compile Include="DuplicateStream.cs" />
<Compile Include="IPackStreamContext.cs" />
<Compile Include="IUnpackStreamContext.cs" />
<Compile Include="OffsetStream.cs" />
<Compile Include="SafeNativeMethods.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Compression.cd" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,381 @@
//---------------------------------------------------------------------
// <copyright file="CompressionEngine.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
/// <summary>
/// Base class for an engine capable of packing and unpacking a particular
/// compressed file format.
/// </summary>
public abstract class CompressionEngine : IDisposable
{
private CompressionLevel compressionLevel;
private bool dontUseTempFiles;
/// <summary>
/// Creates a new instance of the compression engine base class.
/// </summary>
protected CompressionEngine()
{
this.compressionLevel = CompressionLevel.Normal;
}
/// <summary>
/// Disposes the compression engine.
/// </summary>
~CompressionEngine()
{
this.Dispose(false);
}
/// <summary>
/// Occurs when the compression engine reports progress in packing
/// or unpacking an archive.
/// </summary>
/// <seealso cref="ArchiveProgressType"/>
public event EventHandler<ArchiveProgressEventArgs> Progress;
/// <summary>
/// Gets or sets a flag indicating whether temporary files are created
/// and used during compression.
/// </summary>
/// <value>True if temporary files are used; false if compression is done
/// entirely in-memory.</value>
/// <remarks>The value of this property is true by default. Using temporary
/// files can greatly reduce the memory requirement of compression,
/// especially when compressing large archives. However, setting this property
/// to false may yield slightly better performance when creating small
/// archives. Or it may be necessary if the process does not have sufficient
/// privileges to create temporary files.</remarks>
public bool UseTempFiles
{
get
{
return !this.dontUseTempFiles;
}
set
{
this.dontUseTempFiles = !value;
}
}
/// <summary>
/// Compression level to use when compressing files.
/// </summary>
/// <value>A compression level ranging from minimum to maximum compression,
/// or no compression.</value>
public CompressionLevel CompressionLevel
{
get
{
return this.compressionLevel;
}
set
{
this.compressionLevel = value;
}
}
/// <summary>
/// Disposes of resources allocated by the compression engine.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Creates an archive.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="files">The paths of the files in the archive
/// (not external file paths).</param>
/// <exception cref="ArchiveException">The archive could not be
/// created.</exception>
/// <remarks>
/// The stream context implementation may provide a mapping from the
/// file paths within the archive to the external file paths.
/// </remarks>
public void Pack(IPackStreamContext streamContext, IEnumerable<string> files)
{
if (files == null)
{
throw new ArgumentNullException("files");
}
this.Pack(streamContext, files, 0);
}
/// <summary>
/// Creates an archive or chain of archives.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="files">The paths of the files in the archive (not
/// external file paths).</param>
/// <param name="maxArchiveSize">The maximum number of bytes for one
/// archive before the contents are chained to the next archive, or zero
/// for unlimited archive size.</param>
/// <exception cref="ArchiveException">The archive could not be
/// created.</exception>
/// <remarks>
/// The stream context implementation may provide a mapping from the file
/// paths within the archive to the external file paths.
/// </remarks>
public abstract void Pack(
IPackStreamContext streamContext,
IEnumerable<string> files,
long maxArchiveSize);
/// <summary>
/// Checks whether a Stream begins with a header that indicates
/// it is a valid archive.
/// </summary>
/// <param name="stream">Stream for reading the archive file.</param>
/// <returns>True if the stream is a valid archive
/// (with no offset); false otherwise.</returns>
public abstract bool IsArchive(Stream stream);
/// <summary>
/// Gets the offset of an archive that is positioned 0 or more bytes
/// from the start of the Stream.
/// </summary>
/// <param name="stream">A stream for reading the archive.</param>
/// <returns>The offset in bytes of the archive,
/// or -1 if no archive is found in the Stream.</returns>
/// <remarks>The archive must begin on a 4-byte boundary.</remarks>
public virtual long FindArchiveOffset(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
long sectionSize = 4;
long length = stream.Length;
for (long offset = 0; offset <= length - sectionSize; offset += sectionSize)
{
stream.Seek(offset, SeekOrigin.Begin);
if (this.IsArchive(stream))
{
return offset;
}
}
return -1;
}
/// <summary>
/// Gets information about all files in an archive stream.
/// </summary>
/// <param name="stream">A stream for reading the archive.</param>
/// <returns>Information about all files in the archive stream.</returns>
/// <exception cref="ArchiveException">The stream is not a valid
/// archive.</exception>
public IList<ArchiveFileInfo> GetFileInfo(Stream stream)
{
return this.GetFileInfo(new BasicUnpackStreamContext(stream), null);
}
/// <summary>
/// Gets information about files in an archive or archive chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="fileFilter">A predicate that can determine
/// which files to process, optional.</param>
/// <returns>Information about files in the archive stream.</returns>
/// <exception cref="ArchiveException">The archive provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public abstract IList<ArchiveFileInfo> GetFileInfo(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter);
/// <summary>
/// Gets the list of files in an archive Stream.
/// </summary>
/// <param name="stream">A stream for reading the archive.</param>
/// <returns>A list of the paths of all files contained in the
/// archive.</returns>
/// <exception cref="ArchiveException">The stream is not a valid
/// archive.</exception>
public IList<string> GetFiles(Stream stream)
{
return this.GetFiles(new BasicUnpackStreamContext(stream), null);
}
/// <summary>
/// Gets the list of files in an archive or archive chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="fileFilter">A predicate that can determine
/// which files to process, optional.</param>
/// <returns>An array containing the names of all files contained in
/// the archive or archive chain.</returns>
/// <exception cref="ArchiveException">The archive provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public IList<string> GetFiles(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter)
{
if (streamContext == null)
{
throw new ArgumentNullException("streamContext");
}
IList<ArchiveFileInfo> files =
this.GetFileInfo(streamContext, fileFilter);
IList<string> fileNames = new List<string>(files.Count);
for (int i = 0; i < files.Count; i++)
{
fileNames.Add(files[i].Name);
}
return fileNames;
}
/// <summary>
/// Reads a single file from an archive stream.
/// </summary>
/// <param name="stream">A stream for reading the archive.</param>
/// <param name="path">The path of the file within the archive
/// (not the external file path).</param>
/// <returns>A stream for reading the extracted file, or null
/// if the file does not exist in the archive.</returns>
/// <exception cref="ArchiveException">The stream is not a valid
/// archive.</exception>
/// <remarks>The entire extracted file is cached in memory, so this
/// method requires enough free memory to hold the file.</remarks>
public Stream Unpack(Stream stream, string path)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (path == null)
{
throw new ArgumentNullException("path");
}
BasicUnpackStreamContext streamContext =
new BasicUnpackStreamContext(stream);
this.Unpack(
streamContext,
delegate(string match)
{
return String.Compare(
match, path, true, CultureInfo.InvariantCulture) == 0;
});
Stream extractStream = streamContext.FileStream;
if (extractStream != null)
{
extractStream.Position = 0;
}
return extractStream;
}
/// <summary>
/// Extracts files from an archive or archive chain.
/// </summary>
/// <param name="streamContext">A context interface to handle opening
/// and closing of archive and file streams.</param>
/// <param name="fileFilter">An optional predicate that can determine
/// which files to process.</param>
/// <exception cref="ArchiveException">The archive provided
/// by the stream context is not valid.</exception>
/// <remarks>
/// The <paramref name="fileFilter"/> predicate takes an internal file
/// path and returns true to include the file or false to exclude it.
/// </remarks>
public abstract void Unpack(
IUnpackStreamContext streamContext,
Predicate<string> fileFilter);
/// <summary>
/// Called by sublcasses to distribute a packing or unpacking progress
/// event to listeners.
/// </summary>
/// <param name="e">Event details.</param>
protected void OnProgress(ArchiveProgressEventArgs e)
{
if (this.Progress != null)
{
this.Progress(this, e);
}
}
/// <summary>
/// Disposes of resources allocated by the compression engine.
/// </summary>
/// <param name="disposing">If true, the method has been called
/// directly or indirectly by a user's code, so managed and unmanaged
/// resources will be disposed. If false, the method has been called by
/// the runtime from inside the finalizer, and only unmanaged resources
/// will be disposed.</param>
protected virtual void Dispose(bool disposing)
{
}
/// <summary>
/// Compresion utility function for converting old-style
/// date and time values to a DateTime structure.
/// </summary>
public static void DosDateAndTimeToDateTime(
short dosDate, short dosTime, out DateTime dateTime)
{
if (dosDate == 0 && dosTime == 0)
{
dateTime = DateTime.MinValue;
}
else
{
long fileTime;
SafeNativeMethods.DosDateTimeToFileTime(dosDate, dosTime, out fileTime);
dateTime = DateTime.FromFileTimeUtc(fileTime);
dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Local);
}
}
/// <summary>
/// Compresion utility function for converting a DateTime structure
/// to old-style date and time values.
/// </summary>
public static void DateTimeToDosDateAndTime(
DateTime dateTime, out short dosDate, out short dosTime)
{
dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc);
long filetime = dateTime.ToFileTimeUtc();
SafeNativeMethods.FileTimeToDosDateTime(ref filetime, out dosDate, out dosTime);
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
//---------------------------------------------------------------------
// <copyright file="CompressionLevel.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// Specifies the compression level ranging from minimum compresion to
/// maximum compression, or no compression at all.
/// </summary>
/// <remarks>
/// Although only four values are enumerated, any integral value between
/// <see cref="CompressionLevel.Min"/> and <see cref="CompressionLevel.Max"/> can also be used.
/// </remarks>
public enum CompressionLevel
{
/// <summary>Do not compress files, only store.</summary>
None = 0,
/// <summary>Minimum compression; fastest.</summary>
Min = 1,
/// <summary>A compromize between speed and compression efficiency.</summary>
Normal = 6,
/// <summary>Maximum compression; slowest.</summary>
Max = 10
}
}

Просмотреть файл

@ -0,0 +1,222 @@
//---------------------------------------------------------------------
// <copyright file="DuplicateStream.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
/// <summary>
/// Duplicates a source stream by maintaining a separate position.
/// </summary>
/// <remarks>
/// WARNING: duplicate streams are not thread-safe with respect to each other or the original stream.
/// If multiple threads use duplicate copies of the same stream, they must synchronize for any operations.
/// </remarks>
public class DuplicateStream : Stream
{
private Stream source;
private long position;
/// <summary>
/// Creates a new duplicate of a stream.
/// </summary>
/// <param name="source">source of the duplicate</param>
public DuplicateStream(Stream source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
this.source = DuplicateStream.OriginalStream(source);
}
/// <summary>
/// Gets the original stream that was used to create the duplicate.
/// </summary>
public Stream Source
{
get
{
return this.source;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports reading.
/// </summary>
/// <value>true if the stream supports reading; otherwise, false.</value>
public override bool CanRead
{
get
{
return this.source.CanRead;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports writing.
/// </summary>
/// <value>true if the stream supports writing; otherwise, false.</value>
public override bool CanWrite
{
get
{
return this.source.CanWrite;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports seeking.
/// </summary>
/// <value>true if the stream supports seeking; otherwise, false.</value>
public override bool CanSeek
{
get
{
return this.source.CanSeek;
}
}
/// <summary>
/// Gets the length of the source stream.
/// </summary>
public override long Length
{
get
{
return this.source.Length;
}
}
/// <summary>
/// Gets or sets the position of the current stream,
/// ignoring the position of the source stream.
/// </summary>
public override long Position
{
get
{
return this.position;
}
set
{
this.position = value;
}
}
/// <summary>
/// Retrieves the original stream from a possible duplicate stream.
/// </summary>
/// <param name="stream">Possible duplicate stream.</param>
/// <returns>If the stream is a DuplicateStream, returns
/// the duplicate's source; otherwise returns the same stream.</returns>
public static Stream OriginalStream(Stream stream)
{
DuplicateStream dupStream = stream as DuplicateStream;
return dupStream != null ? dupStream.Source : stream;
}
/// <summary>
/// Flushes the source stream.
/// </summary>
public override void Flush()
{
this.source.Flush();
}
/// <summary>
/// Sets the length of the source stream.
/// </summary>
/// <param name="value">The desired length of the stream in bytes.</param>
public override void SetLength(long value)
{
this.source.SetLength(value);
}
/// <summary>
/// Closes the underlying stream, effectively closing ALL duplicates.
/// </summary>
public override void Close()
{
this.source.Close();
}
/// <summary>
/// Reads from the source stream while maintaining a separate position
/// and not impacting the source stream's position.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer
/// contains the specified byte array with the values between offset and
/// (offset + count - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin
/// storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>The total number of bytes read into the buffer. This can be less
/// than the number of bytes requested if that many bytes are not currently available,
/// or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
long saveSourcePosition = this.source.Position;
this.source.Position = this.position;
int read = this.source.Read(buffer, offset, count);
this.position = this.source.Position;
this.source.Position = saveSourcePosition;
return read;
}
/// <summary>
/// Writes to the source stream while maintaining a separate position
/// and not impacting the source stream's position.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count
/// bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which
/// to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the
/// current stream.</param>
public override void Write(byte[] buffer, int offset, int count)
{
long saveSourcePosition = this.source.Position;
this.source.Position = this.position;
this.source.Write(buffer, offset, count);
this.position = this.source.Position;
this.source.Position = saveSourcePosition;
}
/// <summary>
/// Changes the position of this stream without impacting the
/// source stream's position.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type SeekOrigin indicating the reference
/// point used to obtain the new position.</param>
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
long originPosition = 0;
if (origin == SeekOrigin.Current)
{
originPosition = this.position;
}
else if (origin == SeekOrigin.End)
{
originPosition = this.Length;
}
this.position = originPosition + offset;
return this.position;
}
}
}

Просмотреть файл

@ -0,0 +1,127 @@
//---------------------------------------------------------------------
// <copyright file="IPackStreamContext.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// This interface provides the methods necessary for the
/// <see cref="CompressionEngine"/> to open and close streams for archives
/// and files. The implementor of this interface can use any kind of logic
/// to determine what kind of streams to open and where.
/// </summary>
public interface IPackStreamContext
{
/// <summary>
/// Gets the name of the archive with a specified number.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive
/// within the chain.</param>
/// <returns>The name of the requested archive. May be an empty string
/// for non-chained archives, but may never be null.</returns>
/// <remarks>The archive name is the name stored within the archive, used for
/// identification of the archive especially among archive chains. That
/// name is often, but not necessarily the same as the filename of the
/// archive package.</remarks>
string GetArchiveName(int archiveNumber);
/// <summary>
/// Opens a stream for writing an archive package.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive within
/// the chain.</param>
/// <param name="archiveName">The name of the archive that was returned
/// by <see cref="GetArchiveName"/>.</param>
/// <param name="truncate">True if the stream should be truncated when
/// opened (if it already exists); false if an existing stream is being
/// re-opened for writing additional data.</param>
/// <param name="compressionEngine">Instance of the compression engine
/// doing the operations.</param>
/// <returns>A writable Stream where the compressed archive bytes will be
/// written, or null to cancel the archive creation.</returns>
/// <remarks>
/// If this method returns null, the archive engine will throw a
/// FileNotFoundException.
/// </remarks>
Stream OpenArchiveWriteStream(
int archiveNumber,
string archiveName,
bool truncate,
CompressionEngine compressionEngine);
/// <summary>
/// Closes a stream where an archive package was written.
/// </summary>
/// <param name="archiveNumber">The 0-based index of the archive within
/// the chain.</param>
/// <param name="archiveName">The name of the archive that was previously
/// returned by
/// <see cref="GetArchiveName"/>.</param>
/// <param name="stream">A stream that was previously returned by
/// <see cref="OpenArchiveWriteStream"/> and is now ready to be closed.</param>
/// <remarks>
/// If there is another archive package in the chain, then after this stream
/// is closed a new stream will be opened.
/// </remarks>
void CloseArchiveWriteStream(int archiveNumber, string archiveName, Stream stream);
/// <summary>
/// Opens a stream to read a file that is to be included in an archive.
/// </summary>
/// <param name="path">The path of the file within the archive. This is often,
/// but not necessarily, the same as the relative path of the file outside
/// the archive.</param>
/// <param name="attributes">Returned attributes of the opened file, to be
/// stored in the archive.</param>
/// <param name="lastWriteTime">Returned last-modified time of the opened file,
/// to be stored in the archive.</param>
/// <returns>A readable Stream where the file bytes will be read from before
/// they are compressed, or null to skip inclusion of the file and continue to
/// the next file.</returns>
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters")]
Stream OpenFileReadStream(
string path,
out FileAttributes attributes,
out DateTime lastWriteTime);
/// <summary>
/// Closes a stream that has been used to read a file.
/// </summary>
/// <param name="path">The path of the file within the archive; the same as
/// the path provided
/// when the stream was opened.</param>
/// <param name="stream">A stream that was previously returned by
/// <see cref="OpenFileReadStream"/> and is now ready to be closed.</param>
void CloseFileReadStream(string path, Stream stream);
/// <summary>
/// Gets extended parameter information specific to the compression
/// format being used.
/// </summary>
/// <param name="optionName">Name of the option being requested.</param>
/// <param name="parameters">Parameters for the option; for per-file options,
/// the first parameter is typically the internal file path.</param>
/// <returns>Option value, or null to use the default behavior.</returns>
/// <remarks>
/// This method provides a way to set uncommon options during packaging, or a
/// way to handle aspects of compression formats not supported by the base library.
/// <para>For example, this may be used by the zip compression library to
/// specify different compression methods/levels on a per-file basis.</para>
/// <para>The available option names, parameters, and expected return values
/// should be documented by each compression library.</para>
/// </remarks>
object GetOption(string optionName, object[] parameters);
}
}

Просмотреть файл

@ -0,0 +1,81 @@
//---------------------------------------------------------------------
// <copyright file="IUnpackStreamContext.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
/// <summary>
/// This interface provides the methods necessary for the <see cref="CompressionEngine"/> to open
/// and close streams for archives and files. The implementor of this interface can use any
/// kind of logic to determine what kind of streams to open and where
/// </summary>
public interface IUnpackStreamContext
{
/// <summary>
/// Opens the archive stream for reading.
/// </summary>
/// <param name="archiveNumber">The zero-based index of the archive to open.</param>
/// <param name="archiveName">The name of the archive being opened.</param>
/// <param name="compressionEngine">Instance of the compression engine doing the operations.</param>
/// <returns>A stream from which archive bytes are read, or null to cancel extraction
/// of the archive.</returns>
/// <remarks>
/// When the first archive in a chain is opened, the name is not yet known, so the
/// provided value will be an empty string. When opening further archives, the
/// provided value is the next-archive name stored in the previous archive. This
/// name is often, but not necessarily, the same as the filename of the archive
/// package to be opened.
/// <para>If this method returns null, the archive engine will throw a
/// FileNotFoundException.</para>
/// </remarks>
Stream OpenArchiveReadStream(int archiveNumber, string archiveName, CompressionEngine compressionEngine);
/// <summary>
/// Closes a stream where an archive package was read.
/// </summary>
/// <param name="archiveNumber">The archive number of the stream to close.</param>
/// <param name="archiveName">The name of the archive being closed.</param>
/// <param name="stream">The stream that was previously returned by
/// <see cref="OpenArchiveReadStream"/> and is now ready to be closed.</param>
void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream);
/// <summary>
/// Opens a stream for writing extracted file bytes.
/// </summary>
/// <param name="path">The path of the file within the archive. This is often, but
/// not necessarily, the same as the relative path of the file outside the archive.</param>
/// <param name="fileSize">The uncompressed size of the file to be extracted.</param>
/// <param name="lastWriteTime">The last write time of the file to be extracted.</param>
/// <returns>A stream where extracted file bytes are to be written, or null to skip
/// extraction of the file and continue to the next file.</returns>
/// <remarks>
/// The implementor may use the path, size and date information to dynamically
/// decide whether or not the file should be extracted.
/// </remarks>
Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime);
/// <summary>
/// Closes a stream where an extracted file was written.
/// </summary>
/// <param name="path">The path of the file within the archive.</param>
/// <param name="stream">The stream that was previously returned by <see cref="OpenFileWriteStream"/>
/// and is now ready to be closed.</param>
/// <param name="attributes">The attributes of the extracted file.</param>
/// <param name="lastWriteTime">The last write time of the file.</param>
/// <remarks>
/// The implementor may wish to apply the attributes and date to the newly-extracted file.
/// </remarks>
void CloseFileWriteStream(string path, Stream stream, FileAttributes attributes, DateTime lastWriteTime);
}
}

Просмотреть файл

@ -0,0 +1,216 @@
//---------------------------------------------------------------------
// <copyright file="OffsetStream.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.IO;
/// <summary>
/// Wraps a source stream and offsets all read/write/seek calls by a given value.
/// </summary>
/// <remarks>
/// This class is used to trick archive an packing or unpacking process
/// into reading or writing at an offset into a file, primarily for
/// self-extracting packages.
/// </remarks>
public class OffsetStream : Stream
{
private Stream source;
private long sourceOffset;
/// <summary>
/// Creates a new OffsetStream instance from a source stream
/// and using a specified offset.
/// </summary>
/// <param name="source">Underlying stream for which all calls will be offset.</param>
/// <param name="offset">Positive or negative number of bytes to offset.</param>
public OffsetStream(Stream source, long offset)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
this.source = source;
this.sourceOffset = offset;
this.source.Seek(this.sourceOffset, SeekOrigin.Current);
}
/// <summary>
/// Gets the underlying stream that this OffsetStream calls into.
/// </summary>
public Stream Source
{
get { return this.source; }
}
/// <summary>
/// Gets the number of bytes to offset all calls before
/// redirecting to the underlying stream.
/// </summary>
public long Offset
{
get { return this.sourceOffset; }
}
/// <summary>
/// Gets a value indicating whether the source stream supports reading.
/// </summary>
/// <value>true if the stream supports reading; otherwise, false.</value>
public override bool CanRead
{
get
{
return this.source.CanRead;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports writing.
/// </summary>
/// <value>true if the stream supports writing; otherwise, false.</value>
public override bool CanWrite
{
get
{
return this.source.CanWrite;
}
}
/// <summary>
/// Gets a value indicating whether the source stream supports seeking.
/// </summary>
/// <value>true if the stream supports seeking; otherwise, false.</value>
public override bool CanSeek
{
get
{
return this.source.CanSeek;
}
}
/// <summary>
/// Gets the effective length of the stream, which is equal to
/// the length of the source stream minus the offset.
/// </summary>
public override long Length
{
get { return this.source.Length - this.sourceOffset; }
}
/// <summary>
/// Gets or sets the effective position of the stream, which
/// is equal to the position of the source stream minus the offset.
/// </summary>
public override long Position
{
get { return this.source.Position - this.sourceOffset; }
set { this.source.Position = value + this.sourceOffset; }
}
/// <summary>
/// Reads a sequence of bytes from the source stream and advances
/// the position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer
/// contains the specified byte array with the values between offset and
/// (offset + count - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin
/// storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>The total number of bytes read into the buffer. This can be less
/// than the number of bytes requested if that many bytes are not currently available,
/// or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
return this.source.Read(buffer, offset, count);
}
/// <summary>
/// Writes a sequence of bytes to the source stream and advances the
/// current position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">An array of bytes. This method copies count
/// bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which
/// to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the
/// current stream.</param>
public override void Write(byte[] buffer, int offset, int count)
{
this.source.Write(buffer, offset, count);
}
/// <summary>
/// Reads a byte from the stream and advances the position within the
/// source stream by one byte, or returns -1 if at the end of the stream.
/// </summary>
/// <returns>The unsigned byte cast to an Int32, or -1 if at the
/// end of the stream.</returns>
public override int ReadByte()
{
return this.source.ReadByte();
}
/// <summary>
/// Writes a byte to the current position in the source stream and
/// advances the position within the stream by one byte.
/// </summary>
/// <param name="value">The byte to write to the stream.</param>
public override void WriteByte(byte value)
{
this.source.WriteByte(value);
}
/// <summary>
/// Flushes the source stream.
/// </summary>
public override void Flush()
{
this.source.Flush();
}
/// <summary>
/// Sets the position within the current stream, which is
/// equal to the position within the source stream minus the offset.
/// </summary>
/// <param name="offset">A byte offset relative to the origin parameter.</param>
/// <param name="origin">A value of type SeekOrigin indicating
/// the reference point used to obtain the new position.</param>
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
return this.source.Seek(offset + (origin == SeekOrigin.Begin ? this.sourceOffset : 0), origin) - this.sourceOffset;
}
/// <summary>
/// Sets the effective length of the stream, which is equal to
/// the length of the source stream minus the offset.
/// </summary>
/// <param name="value">The desired length of the
/// current stream in bytes.</param>
public override void SetLength(long value)
{
this.source.SetLength(value + this.sourceOffset);
}
/// <summary>
/// Closes the underlying stream.
/// </summary>
public override void Close()
{
this.source.Close();
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
//---------------------------------------------------------------------
// <copyright file="SafeNativeMethods.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Compression
{
using System;
using System.Security;
using System.Runtime.InteropServices;
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DosDateTimeToFileTime(
short wFatDate, short wFatTime, out long fileTime);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool FileTimeToDosDateTime(
ref long fileTime, out short wFatDate, out short wFatTime);
}
}

Просмотреть файл

@ -0,0 +1,35 @@
//---------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyDescription("Classes for reading and writing resource data in executable files")]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
// SECURITY: The UnmanagedCode assertions in the resource classes are safe, because
// appropriate demands are made for file I/O permissions before reading/writing files.
[assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion = true, UnmanagedCode = true)]
// SECURITY: Review carefully!
// This assembly is designed so that partially trusted callers should be able to
// read and write file version info in a path where they have limited
// file I/O permission.
[assembly: AllowPartiallyTrustedCallers]
[assembly: SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "Microsoft.Deployment.Resources.ResourceCollection.#System.Collections.Generic.ICollection`1<Microsoft.Deployment.Resources.Resource>.IsReadOnly")]

Просмотреть файл

@ -0,0 +1,67 @@
//---------------------------------------------------------------------
// <copyright file="BitmapResource.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
/// <summary>
/// A subclass of Resource which provides specific methods for manipulating the resource data.
/// </summary>
/// <remarks>
/// The resource is of type <see cref="ResourceType.Bitmap"/> (RT_GROUPICON).
/// </remarks>
public sealed class BitmapResource : Resource
{
private const int SizeOfBitmapFileHeader = 14; // this is the sizeof(BITMAPFILEHEADER)
/// <summary>
/// Creates a new BitmapResource object without any data. The data can be later loaded from a file.
/// </summary>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
public BitmapResource(string name, int locale)
: this(name, locale, null)
{
}
/// <summary>
/// Creates a new BitmapResource object with data. The data can be later saved to a file.
/// </summary>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
/// <param name="data">Raw resource data</param>
public BitmapResource(string name, int locale, byte[] data)
: base(ResourceType.Bitmap, name, locale, data)
{
}
/// <summary>
/// Reads the bitmap from a .bmp file.
/// </summary>
/// <param name="path">Path to a bitmap file (.bmp).</param>
public void ReadFromFile(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
// Move past the BITMAPFILEHEADER, and copy the rest of the bitmap as the resource data. Resource
// functions expect only the BITMAPINFO struct which exists just beyond the BITMAPFILEHEADER
// struct in bitmap files.
fs.Seek(BitmapResource.SizeOfBitmapFileHeader, SeekOrigin.Begin);
base.Data = new byte[fs.Length - BitmapResource.SizeOfBitmapFileHeader];
fs.Read(base.Data, 0, base.Data.Length);
}
}
}
}

Просмотреть файл

@ -0,0 +1,193 @@
//---------------------------------------------------------------------
// <copyright file="FixedFileVersionInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
internal class FixedFileVersionInfo
{
public FixedFileVersionInfo()
{
// Set reasonable defaults
this.signature = 0xFEEF04BD;
this.structVersion = 0x00010000; // v1.0
this.FileVersion = new Version(0, 0, 0, 0);
this.ProductVersion = new Version(0, 0, 0, 0);
this.FileFlagsMask = VersionBuildTypes.Debug | VersionBuildTypes.Prerelease;
this.FileFlags = VersionBuildTypes.None;
this.FileOS = VersionFileOS.NT_WINDOWS32;
this.FileType = VersionFileType.Application;
this.FileSubtype = VersionFileSubtype.Unknown;
this.Timestamp = DateTime.MinValue;
}
private uint signature;
private uint structVersion;
public Version FileVersion
{
get
{
return this.fileVersion;
}
set
{
if (value == null)
{
throw new InvalidOperationException();
}
this.fileVersion = value;
}
}
private Version fileVersion;
public Version ProductVersion
{
get
{
return this.productVersion;
}
set
{
if (value == null)
{
throw new InvalidOperationException();
}
this.productVersion = value;
}
}
private Version productVersion;
public VersionBuildTypes FileFlagsMask
{
get { return this.fileFlagsMask; }
set { this.fileFlagsMask = value; }
}
private VersionBuildTypes fileFlagsMask;
public VersionBuildTypes FileFlags
{
get { return this.fileFlags; }
set { this.fileFlags = value; }
}
private VersionBuildTypes fileFlags;
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public VersionFileOS FileOS
{
get { return this.fileOS; }
set { this.fileOS = value; }
}
private VersionFileOS fileOS;
public VersionFileType FileType
{
get { return this.fileType; }
set { this.fileType = value; }
}
private VersionFileType fileType;
public VersionFileSubtype FileSubtype
{
get { return this.fileSubtype; }
set { this.fileSubtype = value; }
}
private VersionFileSubtype fileSubtype;
public DateTime Timestamp
{
get { return this.timestamp; }
set { this.timestamp = value; }
}
private DateTime timestamp;
public void Read(BinaryReader reader)
{
this.signature = reader.ReadUInt32();
this.structVersion = reader.ReadUInt32();
this.fileVersion = UInt64ToVersion(reader.ReadUInt64());
this.productVersion = UInt64ToVersion(reader.ReadUInt64());
this.fileFlagsMask = (VersionBuildTypes) reader.ReadInt32();
this.fileFlags = (VersionBuildTypes) reader.ReadInt32();
this.fileOS = (VersionFileOS) reader.ReadInt32();
this.fileType = (VersionFileType) reader.ReadInt32();
this.fileSubtype = (VersionFileSubtype) reader.ReadInt32();
this.timestamp = UInt64ToDateTime(reader.ReadUInt64());
}
public void Write(BinaryWriter writer)
{
writer.Write(this.signature);
writer.Write(this.structVersion);
writer.Write(VersionToUInt64(this.fileVersion));
writer.Write(VersionToUInt64(this.productVersion));
writer.Write((int) this.fileFlagsMask);
writer.Write((int) this.fileFlags);
writer.Write((int) this.fileOS);
writer.Write((int) this.fileType);
writer.Write((int) this.fileSubtype);
writer.Write(DateTimeToUInt64(this.timestamp));
}
public static explicit operator FixedFileVersionInfo(byte[] bytesValue)
{
FixedFileVersionInfo ffviValue = new FixedFileVersionInfo();
using (BinaryReader reader = new BinaryReader(new MemoryStream(bytesValue, false)))
{
ffviValue.Read(reader);
}
return ffviValue;
}
public static explicit operator byte[](FixedFileVersionInfo ffviValue)
{
const int FFVI_LENGTH = 52;
byte[] bytesValue = new byte[FFVI_LENGTH];
using (BinaryWriter writer = new BinaryWriter(new MemoryStream(bytesValue, true)))
{
ffviValue.Write(writer);
}
return bytesValue;
}
private static Version UInt64ToVersion(ulong version)
{
return new Version((int) ((version >> 16) & 0xFFFF), (int) (version & 0xFFFF), (int) (version >> 48), (int) ((version >> 32) & 0xFFFF));
}
private static ulong VersionToUInt64(Version version)
{
return (((ulong) (ushort) version.Major) << 16) | ((ulong) (ushort) version.Minor)
| (((ulong) (ushort) version.Build) << 48) | (((ulong) (ushort) version.Revision) << 32);
}
private static DateTime UInt64ToDateTime(ulong dateTime)
{
return (dateTime == 0 ? DateTime.MinValue : DateTime.FromFileTime((long) dateTime));
}
private static ulong DateTimeToUInt64(DateTime dateTime)
{
return (dateTime == DateTime.MinValue ? 0 : (ulong) dateTime.ToFileTime());
}
}
}

Просмотреть файл

@ -0,0 +1,129 @@
//---------------------------------------------------------------------
// <copyright file="GroupIconInfo.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
internal enum GroupIconType
{
Unknown,
Icon,
Cursor,
}
internal struct GroupIconDirectoryInfo
{
public byte width;
public byte height;
public byte colors;
public byte reserved;
public ushort planes;
public ushort bitsPerPixel;
public uint imageSize;
public uint imageOffset; // only valid when icon group is read from .ico file.
public ushort imageIndex; // only valid when icon group is read from PE resource.
}
internal class GroupIconInfo
{
private ushort reserved;
private GroupIconType type;
private GroupIconDirectoryInfo[] images;
public GroupIconInfo()
{
this.images = new GroupIconDirectoryInfo[0];
}
public GroupIconDirectoryInfo[] DirectoryInfo { get { return this.images; } }
public void ReadFromFile(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
this.Read(reader, true);
}
public void ReadFromResource(byte[] data)
{
using (BinaryReader reader = new BinaryReader(new MemoryStream(data, false)))
{
this.Read(reader, false);
}
}
public byte[] GetResourceData()
{
byte[] data = null;
using (MemoryStream stream = new MemoryStream())
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(this.reserved);
writer.Write((ushort)this.type);
writer.Write((ushort)this.images.Length);
for (int i = 0; i < this.images.Length; ++i)
{
writer.Write(this.images[i].width);
writer.Write(this.images[i].height);
writer.Write(this.images[i].colors);
writer.Write(this.images[i].reserved);
writer.Write(this.images[i].planes);
writer.Write(this.images[i].bitsPerPixel);
writer.Write(this.images[i].imageSize);
writer.Write(this.images[i].imageIndex);
}
data = new byte[stream.Length];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(data, 0, data.Length);
}
return data;
}
private void Read(BinaryReader reader, bool readFromFile)
{
this.reserved = reader.ReadUInt16();
this.type = (GroupIconType)reader.ReadUInt16();
int imageCount = reader.ReadUInt16();
this.images = new GroupIconDirectoryInfo[imageCount];
for (int i = 0; i < imageCount; ++i)
{
this.images[i].width = reader.ReadByte();
this.images[i].height = reader.ReadByte();
this.images[i].colors = reader.ReadByte();
this.images[i].reserved = reader.ReadByte();
this.images[i].planes = reader.ReadUInt16();
this.images[i].bitsPerPixel = reader.ReadUInt16();
this.images[i].imageSize = reader.ReadUInt32();
if (readFromFile)
{
this.images[i].imageOffset = reader.ReadUInt32();
this.images[i].imageIndex = (ushort)(i + 1);
}
else
{
this.images[i].imageIndex = reader.ReadUInt16();
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,130 @@
//---------------------------------------------------------------------
// <copyright file="GroupIconResource.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// A subclass of Resource which provides specific methods for manipulating the resource data.
/// </summary>
/// <remarks>
/// The resource is of type <see cref="ResourceType.GroupIcon"/> (RT_GROUPICON).
/// </remarks>
public sealed class GroupIconResource : Resource
{
internal bool dirty;
private GroupIconInfo rawGroupIconInfo;
private List<Resource> icons;
/// <summary>
/// Creates a new GroupIconResource object without any data. The data can be later loaded from a file.
/// </summary>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
public GroupIconResource(string name, int locale)
: this(name, locale, null)
{
}
/// <summary>
/// Creates a new GroupIconResource object with data. The data can be later saved to a file.
/// </summary>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
/// <param name="data">Raw resource data</param>
public GroupIconResource(string name, int locale, byte[] data)
: base(ResourceType.GroupIcon, name, locale, data)
{
this.RefreshIconGroupInfo(data);
}
/// <summary>
/// Gets or sets the raw data of the resource. The data is in the format of the RT_GROUPICON resource structure.
/// </summary>
public override byte[] Data
{
get
{
if (this.dirty)
{
base.Data = this.rawGroupIconInfo.GetResourceData();
this.dirty = false;
}
return base.Data;
}
set
{
this.RefreshIconGroupInfo(value);
base.Data = value;
this.dirty = false;
}
}
/// <summary>
/// Enumerates the the icons in the icon group.
/// </summary>
public IEnumerable<Resource> Icons { get { return this.icons; } }
/// <summary>
/// Reads the icon group from a .ico file.
/// </summary>
/// <param name="path">Path to an icon file (.ico).</param>
public void ReadFromFile(string path)
{
this.rawGroupIconInfo = new GroupIconInfo();
this.icons = new List<Resource>();
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
{
this.rawGroupIconInfo.ReadFromFile(fs);
// After reading the group icon info header from the file, read all the icons.
for (int i = 0; i < this.rawGroupIconInfo.DirectoryInfo.Length; ++i)
{
ushort index = this.rawGroupIconInfo.DirectoryInfo[i].imageIndex;
uint offset = this.rawGroupIconInfo.DirectoryInfo[i].imageOffset;
uint size = this.rawGroupIconInfo.DirectoryInfo[i].imageSize;
byte[] data = new byte[size];
fs.Seek(offset, SeekOrigin.Begin);
fs.Read(data, 0, data.Length);
Resource resource = new Resource(ResourceType.Icon, String.Concat("#", index), this.Locale, data);
this.icons.Add(resource);
}
}
this.dirty = true;
}
private void RefreshIconGroupInfo(byte[] refreshData)
{
this.rawGroupIconInfo = new GroupIconInfo();
this.icons = new List<Resource>();
if (refreshData != null)
{
this.rawGroupIconInfo.ReadFromResource(refreshData);
}
this.dirty = true;
}
}
}

Просмотреть файл

@ -0,0 +1,65 @@
//---------------------------------------------------------------------
// <copyright file="NativeMethods.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibraryEx(string fileName, IntPtr hFile, uint flags);
internal const uint LOAD_LIBRARY_AS_DATAFILE = 2;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool FreeLibrary(IntPtr module);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumResourceTypes(IntPtr module, EnumResTypesProc enumFunc, IntPtr param);
[return: MarshalAs(UnmanagedType.Bool)]
internal delegate bool EnumResTypesProc(IntPtr module, IntPtr type, IntPtr param);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumResourceNames(IntPtr module, IntPtr type, EnumResNamesProc enumFunc, IntPtr param);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumResourceNames(IntPtr module, string type, EnumResNamesProc enumFunc, IntPtr param);
[return: MarshalAs(UnmanagedType.Bool)]
internal delegate bool EnumResNamesProc(IntPtr module, IntPtr type, IntPtr name, IntPtr param);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumResourceLanguages(IntPtr module, IntPtr type, IntPtr name, EnumResLangsProc enumFunc, IntPtr param);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumResourceLanguages(IntPtr module, string type, string name, EnumResLangsProc enumFunc, IntPtr param);
[return: MarshalAs(UnmanagedType.Bool)]
internal delegate bool EnumResLangsProc(IntPtr module, IntPtr type, IntPtr name, ushort langId, IntPtr param);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr FindResourceEx(IntPtr module, string type, string name, ushort langId);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadResource(IntPtr module, IntPtr resourceInfo);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LockResource(IntPtr resourceData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern uint SizeofResource(IntPtr module, IntPtr resourceInfo);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr BeginUpdateResource(string fileName, [MarshalAs(UnmanagedType.Bool)] bool deleteExistingResources);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateResource(IntPtr updateHandle, IntPtr type, IntPtr name, ushort lcid, IntPtr data, uint dataSize);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateResource(IntPtr updateHandle, IntPtr type, string name, ushort lcid, IntPtr data, uint dataSize);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateResource(IntPtr updateHandle, string type, string name, ushort lcid, IntPtr data, uint dataSize);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EndUpdateResource(IntPtr updateHandle, [MarshalAs(UnmanagedType.Bool)] bool discardChanges);
}
}

Просмотреть файл

@ -0,0 +1,244 @@
//---------------------------------------------------------------------
// <copyright file="Resource.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Security.Permissions;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Represents a Win32 resource which can be loaded from and saved to a PE file.
/// </summary>
public class Resource
{
private ResourceType type;
private string name;
private int locale;
private byte[] data;
/// <summary>
/// Creates a new Resource object without any data. The data can be later loaded from a file.
/// </summary>
/// <param name="type">Type of the resource; may be one of the ResourceType constants or a user-defined type.</param>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
public Resource(ResourceType type, string name, int locale)
: this(type, name, locale, null)
{
}
/// <summary>
/// Creates a new Resource object with data. The data can be later saved to a file.
/// </summary>
/// <param name="type">Type of the resource; may be one of the ResourceType constants or a user-defined type.</param>
/// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param>
/// <param name="locale">Locale of the resource</param>
/// <param name="data">Raw resource data</param>
public Resource(ResourceType type, string name, int locale, byte[] data)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
this.type = type;
this.name = name;
this.locale = locale;
this.data = data;
}
/// <summary>
/// Gets or sets the type of the resource. This may be one of the ResourceType constants
/// or a user-defined type name.
/// </summary>
public ResourceType ResourceType
{
get { return this.type; }
set { this.type = value; }
}
/// <summary>
/// Gets or sets the name of the resource. For a numeric resource identifier, the decimal number is prefixed with a "#".
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
this.name = value;
}
}
/// <summary>
/// Gets or sets the locale of the resource.
/// </summary>
public int Locale
{
get { return this.locale; }
set { this.locale = value; }
}
/// <summary>
/// Gets or sets the raw data of the resource.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public virtual byte[] Data
{
get { return this.data; }
set { this.data = value; }
}
/// <summary>
/// Loads the resource data from a file. The file is searched for a resource with matching type, name, and locale.
/// </summary>
/// <param name="file">Win32 PE file containing the resource</param>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Load(string file)
{
new FileIOPermission(FileIOPermissionAccess.Read, file).Demand();
IntPtr module = NativeMethods.LoadLibraryEx(file, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
try
{
this.Load(module);
}
finally
{
NativeMethods.FreeLibrary(module);
}
}
internal void Load(IntPtr module)
{
IntPtr resourceInfo = NativeMethods.FindResourceEx(module, (string) this.ResourceType, this.Name, (ushort) this.Locale);
if (resourceInfo != IntPtr.Zero)
{
uint resourceLength = NativeMethods.SizeofResource(module, resourceInfo);
IntPtr resourceData = NativeMethods.LoadResource(module, resourceInfo);
IntPtr resourcePtr = NativeMethods.LockResource(resourceData);
byte[] resourceBytes = new byte[resourceLength];
Marshal.Copy(resourcePtr, resourceBytes, 0, resourceBytes.Length);
this.Data = resourceBytes;
}
else
{
this.Data = null;
}
}
/// <summary>
/// Saves the resource to a file. Any existing resource data with matching type, name, and locale is overwritten.
/// </summary>
/// <param name="file">Win32 PE file to contain the resource</param>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Save(string file)
{
new FileIOPermission(FileIOPermissionAccess.AllAccess, file).Demand();
IntPtr updateHandle = IntPtr.Zero;
try
{
updateHandle = NativeMethods.BeginUpdateResource(file, false);
this.Save(updateHandle);
if (!NativeMethods.EndUpdateResource(updateHandle, false))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to save resource. Error code: {0}", err));
}
updateHandle = IntPtr.Zero;
}
finally
{
if (updateHandle != IntPtr.Zero)
{
NativeMethods.EndUpdateResource(updateHandle, true);
}
}
}
internal void Save(IntPtr updateHandle)
{
IntPtr dataPtr = IntPtr.Zero;
try
{
int dataLength = 0;
if (this.Data != null)
{
dataLength = this.Data.Length;
dataPtr = Marshal.AllocHGlobal(dataLength);
Marshal.Copy(this.Data, 0, dataPtr, dataLength);
}
bool updateSuccess;
if (this.Name.StartsWith("#", StringComparison.Ordinal))
{
// A numeric-named resource must be saved via the integer version of UpdateResource.
IntPtr intName = new IntPtr(Int32.Parse(this.Name.Substring(1), CultureInfo.InvariantCulture));
updateSuccess = NativeMethods.UpdateResource(updateHandle, new IntPtr(this.ResourceType.IntegerValue), intName, (ushort) this.Locale, dataPtr, (uint) dataLength);
}
else
{
updateSuccess = NativeMethods.UpdateResource(updateHandle, (string) this.ResourceType, this.Name, (ushort) this.Locale, dataPtr, (uint) dataLength);
}
if (!updateSuccess)
{
throw new IOException("Failed to save resource. Error: " + Marshal.GetLastWin32Error());
}
}
finally
{
if (dataPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(dataPtr);
}
}
}
/// <summary>
/// Tests if type, name, and locale of this Resource object match another Resource object.
/// </summary>
/// <param name="obj">Resource object to be compared</param>
/// <returns>True if the objects represent the same resource; false otherwise.</returns>
public override bool Equals(object obj)
{
Resource res = obj as Resource;
if (res == null) return false;
return this.ResourceType == res.ResourceType && this.Name == res.Name && this.Locale == res.Locale;
}
/// <summary>
/// Gets a hash code for this Resource object.
/// </summary>
/// <returns>Hash code generated from the resource type, name, and locale.</returns>
public override int GetHashCode()
{
return this.ResourceType.GetHashCode() ^ this.Name.GetHashCode() ^ this.Locale.GetHashCode();
}
}
}

Просмотреть файл

@ -0,0 +1,371 @@
//---------------------------------------------------------------------
// <copyright file="ResourceCollection.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.IO;
using System.Text;
using System.Security.Permissions;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Allows reading and editing of resource data in a Win32 PE file.
/// </summary>
/// <remarks>
/// To use this class:<list type="number">
/// <item>Create a new ResourceCollection</item>
/// <item>Locate resources for the collection by calling one of the <see cref="ResourceCollection.Find(string)"/> methods</item>
/// <item>Load data of one or more <see cref="Resource"/>s from a file by calling the <see cref="Load"/> method of the
/// Resource class, or load them all at once (more efficient) with the <see cref="Load"/> method of the ResourceCollection.</item>
/// <item>Read and/or edit data of the individual Resource objects using the methods on that class.</item>
/// <item>Save data of one or more <see cref="Resource"/>s to a file by calling the <see cref="Save"/> method of the
/// Resource class, or save them all at once (more efficient) with the <see cref="Save"/> method of the ResourceCollection.</item>
/// </list>
/// </remarks>
public class ResourceCollection : ICollection<Resource>
{
private List<Resource> resources;
/// <summary>
/// Creates a new, empty ResourceCollection.
/// </summary>
public ResourceCollection()
{
this.resources = new List<Resource>();
}
/// <summary>
/// Locates all resources in a file, including all resource types and languages. For each located resource,
/// a <see cref="Resource"/> instance (or subclass) is added to the collection.
/// </summary>
/// <param name="resFile">The file to be searched for resources.</param>
/// <exception cref="IOException">resources could not be read from the file</exception>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Find(string resFile)
{
new FileIOPermission(FileIOPermissionAccess.Read, resFile).Demand();
this.Clear();
IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
if (module == IntPtr.Zero)
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to load resource file. Error code: {0}", err));
}
try
{
if (!NativeMethods.EnumResourceTypes(module, new NativeMethods.EnumResTypesProc(this.EnumResTypes), IntPtr.Zero))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to enumerate resources. Error code: {0}", err));
}
}
finally
{
NativeMethods.FreeLibrary(module);
}
}
/// <summary>
/// Locates all resources in a file of a given type, including all languages. For each located resource,
/// a <see cref="Resource"/> instance (or subclass) is added to the collection.
/// </summary>
/// <param name="resFile">The file to be searched for resources.</param>
/// <param name="type">The type of resource to search for; may be one of the ResourceType constants or a user-defined type.</param>
/// <exception cref="IOException">resources could not be read from the file</exception>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Find(string resFile, ResourceType type)
{
new FileIOPermission(FileIOPermissionAccess.Read, resFile).Demand();
this.Clear();
IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
try
{
if (!NativeMethods.EnumResourceNames(module, (string) type, new NativeMethods.EnumResNamesProc(this.EnumResNames), IntPtr.Zero))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceNames error. Error code: {0}", err));
}
}
finally
{
NativeMethods.FreeLibrary(module);
}
}
/// <summary>
/// Locates all resources in a file of a given type and language. For each located resource,
/// a <see cref="Resource"/> instance (or subclass) is added to the collection.
/// </summary>
/// <param name="resFile">The file to be searched for resources.</param>
/// <param name="type">The type of resource to search for; may be one of the ResourceType constants or a user-defined type.</param>
/// <param name="name">The name of the resource to search for.</param>
/// <exception cref="IOException">resources could not be read from the file</exception>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Find(string resFile, ResourceType type, string name)
{
new FileIOPermission(FileIOPermissionAccess.Read, resFile).Demand();
this.Clear();
IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
try
{
if (!NativeMethods.EnumResourceLanguages(module, (string) type, name, new NativeMethods.EnumResLangsProc(this.EnumResLangs), IntPtr.Zero))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceLanguages error. Error code: {0}", err));
}
}
finally
{
NativeMethods.FreeLibrary(module);
}
}
private bool EnumResTypes(IntPtr module, IntPtr type, IntPtr param)
{
if (!NativeMethods.EnumResourceNames(module, type, new NativeMethods.EnumResNamesProc(EnumResNames), IntPtr.Zero))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceNames error! Error code: {0}", err));
}
return true;
}
private bool EnumResNames(IntPtr module, IntPtr type, IntPtr name, IntPtr param)
{
if (!NativeMethods.EnumResourceLanguages(module, type, name, new NativeMethods.EnumResLangsProc(EnumResLangs), IntPtr.Zero))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceLanguages error. Error code: {0}", err));
}
return true;
}
private bool EnumResLangs(IntPtr module, IntPtr type, IntPtr name, ushort langId, IntPtr param)
{
Resource res;
if (((int) type) == ResourceType.Version.IntegerValue)
{
res = new VersionResource(ResourceNameToString(name), langId);
}
else
{
res = new Resource(ResourceNameToString(type), ResourceNameToString(name), langId);
}
if (!this.Contains(res))
{
this.Add(res);
}
return true;
}
private static string ResourceNameToString(IntPtr resName)
{
if ((resName.ToInt64() >> 16) == 0)
{
return "#" + resName.ToString();
}
else
{
return Marshal.PtrToStringAuto(resName);
}
}
/// <summary>
/// For all resources in the collection, loads their data from a resource file.
/// </summary>
/// <param name="file">The file from which resources are loaded.</param>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Load(string file)
{
new FileIOPermission(FileIOPermissionAccess.Read, file).Demand();
IntPtr module = NativeMethods.LoadLibraryEx(file, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
try
{
foreach (Resource res in this)
{
res.Load(module);
}
}
finally
{
NativeMethods.FreeLibrary(module);
}
}
/// <summary>
/// For all resources in the collection, saves their data to a resource file.
/// </summary>
/// <param name="file">The file to which resources are saved.</param>
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
public void Save(string file)
{
new FileIOPermission(FileIOPermissionAccess.AllAccess, file).Demand();
IntPtr updateHandle = IntPtr.Zero;
try
{
updateHandle = NativeMethods.BeginUpdateResource(file, false);
foreach (Resource res in this)
{
res.Save(updateHandle);
}
if (!NativeMethods.EndUpdateResource(updateHandle, false))
{
int err = Marshal.GetLastWin32Error();
throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to save resource. Error {0}", err));
}
updateHandle = IntPtr.Zero;
}
finally
{
if (updateHandle != IntPtr.Zero)
{
NativeMethods.EndUpdateResource(updateHandle, true);
}
}
}
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
public Resource this[int index]
{
get
{
return (Resource) this.resources[index];
}
set
{
this.resources[index] = value;
}
}
/// <summary>
/// Adds a new item to the collection.
/// </summary>
/// <param name="item">The Resource to add.</param>
public void Add(Resource item)
{
this.resources.Add(item);
}
/// <summary>
/// Removes an item to the collection.
/// </summary>
/// <param name="item">The Resource to remove.</param>
public bool Remove(Resource item)
{
return this.resources.Remove(item);
}
/// <summary>
/// Gets the index of an item in the collection.
/// </summary>
/// <param name="item">The Resource to search for.</param>
/// <returns>The index of the item, or -1 if not found.</returns>
public int IndexOf(Resource item)
{
return this.resources.IndexOf(item);
}
/// <summary>
/// Inserts a item into the collection.
/// </summary>
/// <param name="index">The insertion index.</param>
/// <param name="item">The Resource to insert.</param>
public void Insert(int index, Resource item)
{
this.resources.Insert(index, item);
}
/// <summary>
/// Tests if the collection contains an item.
/// </summary>
/// <param name="item">The Resource to search for.</param>
/// <returns>true if the item is found; false otherwise</returns>
public bool Contains(Resource item)
{
return this.resources.Contains(item);
}
/// <summary>
/// Copies the collection into an array.
/// </summary>
/// <param name="array">The array to copy into.</param>
/// <param name="arrayIndex">The starting index in the destination array.</param>
public void CopyTo(Resource[] array, int arrayIndex)
{
this.resources.CopyTo(array, arrayIndex);
}
/// <summary>
/// Removes all resources from the collection.
/// </summary>
public void Clear()
{
this.resources.Clear();
}
/// <summary>
/// Gets the number of resources in the collection.
/// </summary>
public int Count
{
get
{
return this.resources.Count;
}
}
/// <summary>
/// Gets an enumerator over all resources in the collection.
/// </summary>
/// <returns></returns>
public IEnumerator<Resource> GetEnumerator()
{
return this.resources.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) this.resources).GetEnumerator();
}
bool ICollection<Resource>.IsReadOnly
{
get
{
return false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,208 @@
//---------------------------------------------------------------------
// <copyright file="ResourceType.cs" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file LICENSE.TXT
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
// <summary>
// Part of the Deployment Tools Foundation project.
// </summary>
//---------------------------------------------------------------------
namespace Microsoft.Deployment.Resources
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
/// <summary>
/// Represents either a standard integer resource type or a custom resource type name.
/// </summary>
public class ResourceType
{
// Silence warnings about doc-comments
#pragma warning disable 1591
public static ResourceType None { get { return "#0"; } }
public static ResourceType Cursor { get { return "#1"; } }
public static ResourceType Bitmap { get { return "#2"; } }
public static ResourceType Icon { get { return "#3"; } }
public static ResourceType Menu { get { return "#4"; } }
public static ResourceType Dialog { get { return "#5"; } }
public static ResourceType String { get { return "#6"; } }
public static ResourceType FontDir { get { return "#7"; } }
public static ResourceType Font { get { return "#8"; } }
public static ResourceType Accelerator { get { return "#9"; } }
public static ResourceType RCData { get { return "#10"; } }
public static ResourceType MessageTable { get { return "#11"; } }
public static ResourceType GroupCursor { get { return "#12"; } }
public static ResourceType GroupIcon { get { return "#14"; } }
public static ResourceType Version { get { return "#16"; } }
public static ResourceType DialogInclude { get { return "#17"; } }
public static ResourceType PlugPlay { get { return "#19"; } }
public static ResourceType Vxd { get { return "#20"; } }
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ani")]
public static ResourceType AniCursor { get { return "#21"; } }
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ani")]
public static ResourceType AniIcon { get { return "#22"; } }
public static ResourceType Html { get { return "#23"; } }
public static ResourceType Manifest { get { return "#24"; } }
#pragma warning restore 1591
private string resourceType;
/// <summary>
/// Creates a new resource type from a string resource name.
/// </summary>
/// <param name="resourceType">String resource name,
/// or an integer resource type prefixed by a #.</param>
public ResourceType(string resourceType)
{
if (string.IsNullOrEmpty(resourceType))
{
throw new ArgumentNullException("resourceType");
}
this.resourceType = resourceType;
if (this.IsInteger && this.IntegerValue < 0)
{
throw new ArgumentOutOfRangeException("Invalid integer resource type value.");
}
}
/// <summary>
/// Creates a new integer resource type.
/// </summary>
/// <param name="resourceType">Integer value of a well-known resource type.</param>
public ResourceType(int resourceType)
: this("#" + resourceType)
{
}
/// <summary>
/// Gets a flag indicating whether the resource type is an integer type.
/// </summary>
public bool IsInteger
{
get
{
return this.resourceType.StartsWith("#", StringComparison.Ordinal);
}
}
/// <summary>
/// Gets the integer value of the resource type, or -1 if the resource type is not an integer.
/// </summary>
public int IntegerValue
{
get
{
int value;
if (!this.IsInteger ||
!Int32.TryParse(this.resourceType.Substring(1), out value))
{
value = -1;
}
return value;
}
}
/// <summary>
/// Gets a string representation of the resource type.
/// </summary>
/// <returns>The custom resource name, or the name of a well-known resource type.</returns>
public override string ToString()
{
if (this.IsInteger)
{
switch (this.IntegerValue)
{
case 0: return "None";
case 1: return "Cursor";
case 2: return "Bitmap";
case 3: return "Icon";
case 4: return "Menu";
case 5: return "Dialog";
case 6: return "String";
case 7: return "FontDir";
case 8: return "Font";
case 9: return "Accelerator";
case 10: return "RCData";
case 11: return "MessageTable";
case 12: return "GroupCursor";
case 14: return "GroupIcon";
case 16: return "Version";
case 17: return "DialogInclude";
case 19: return "PlugPlay";
case 20: return "Vxd";
case 21: return "AniCursor";
case 22: return "AniIcon";
case 23: return "Html";
case 24: return "Manifest";
}
}
return this.resourceType;
}
/// <summary>
/// Tests whether one resource type equals another object.
/// </summary>
/// <param name="obj">Other object.</param>
/// <returns>True if equal, else false.</returns>
public override bool Equals(object obj)
{
return this.Equals(obj as ResourceType);
}
/// <summary>
/// Tests whether one resource type equals another.
/// </summary>
/// <param name="otherType">Other resource type.</param>
/// <returns>True if equal, else false.</returns>
public bool Equals(ResourceType otherType)
{
return otherType != null && this.resourceType.Equals(otherType.resourceType, StringComparison.Ordinal);
}
/// <summary>
/// Gets a hash code suitable for using the resource type as a dictionary key.
/// </summary>
/// <returns>Hash code based on the resource type string.</returns>
public override int GetHashCode()
{
return this.resourceType.GetHashCode();
}
/// <summary>
/// Implicitly converts a string to a ResourceType.
/// </summary>
/// <param name="resourceType">String resource type to convert.</param>
/// <returns>ResourceType object.</returns>
public static implicit operator ResourceType(string resourceType)
{
return new ResourceType(resourceType);
}
/// <summary>
/// Explicitly converts a ResourceType to a string.
/// </summary>
/// <param name="resourceType">ResourceType object to convert.</param>
/// <returns>The resource type string.</returns>
/// <remarks>
/// Unlike <see cref="ToString" />, this conversion does not return
/// the common name of well-known integer resource types. Therefore,
/// the returned string is suitable for passing directly to Win32
/// resource APIs that accept resource type strings.
/// </remarks>
public static explicit operator string(ResourceType resourceType)
{
return resourceType.resourceType;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<copyright file="Resources.csproj" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file LICENSE.TXT
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{44931ECB-8D6F-4C12-A872-64E261B6A98E}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.Deployment.Resources</RootNamespace>
<AssemblyName>Microsoft.Deployment.Resources</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<CreateDocumentationFile>true</CreateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="BitmapResource.cs" />
<Compile Include="FixedFileVersionInfo.cs" />
<Compile Include="GroupIconInfo.cs" />
<Compile Include="GroupIconResource.cs" />
<Compile Include="NativeMethods.cs" />
<Compile Include="Resource.cs" />
<Compile Include="ResourceCollection.cs" />
<Compile Include="ResourceType.cs" />
<Compile Include="VersionEnums.cs" />
<Compile Include="VersionInfo.cs" />
<Compile Include="VersionResource.cs" />
<Compile Include="VersionStringTable.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше