diff --git a/.gitattributes b/.gitattributes index 7003c01..3b18559 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,7 +15,7 @@ LICENSE text # Projects and solutions -*.sln text +*.sln binary *.csproj text *.wixproj text diff --git a/.hgeol b/.hgeol index 67fdd71..5d5447a 100644 --- a/.hgeol +++ b/.hgeol @@ -1,37 +1,8 @@ [patterns] -# Non human-editable files are binary - -**.dsp = BIN -**.dsw = BIN -**.mk = BIN **.sln = BIN -**.vcproj = BIN -**.vsprops = BIN - -**.aif = BIN -**.aifc = BIN -**.aiff = BIN -**.au = BIN -**.bmp = BIN -**.db = BIN -**.exe = BIN -**.icns = BIN -**.gif = BIN **.ico = BIN -**.info = BIN -**.jpg = BIN -**.pck = BIN -**.png = BIN -**.psd = BIN -**.tar = BIN -**.wav = BIN -**.whl = BIN -**.xar = BIN -**.zip = BIN - -# Windows batch files work best with CRLF, there can be subtle problems with LF -**.bat = CRLF +**.snk = BIN # All other files (which presumably are human-editable) are "native". # This must be the last rule! diff --git a/Build/BuildReleaseHelpers.psm1 b/Build/BuildReleaseHelpers.psm1 index 82a8829..e663a83 100644 --- a/Build/BuildReleaseHelpers.psm1 +++ b/Build/BuildReleaseHelpers.psm1 @@ -1,240 +1,240 @@ -function submit_symbols { - param($buildname, $buildid, $filetype, $sourcedir, $contacts) - - $request = ` - "BuildId=$buildid $filetype - BuildLabPhone=7058786 - BuildRemark=$buildname - ContactPeople=$contacts - Directory=$sourcedir - Project=TechnicalComputing - Recursive=yes - StatusMail=$contacts - UserName=$env:username" - - Write-Output "*** Symbol Submission Text *** -$request" - - $request | Out-File -Encoding ascii -FilePath request_$filetype.txt - \\symbols\tools\createrequest.cmd -i request_$filetype.txt -d .\SymSrvRequestLogs -c -s -} - -function _find_sdk_tool { - param($tool) - - $_tool_item = "" - foreach ($ver in ("v8.1A", "v8.0A")) { - foreach ($kit in ("WinSDK-NetFx40Tools-x64", "WinSDK-NetFx40Tools-x86", "WinSDK-NetFx40Tools")) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) - if (-not $_kit_path) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) - } - - if ($_kit_path -and (Test-Path $_kit_path.InstallationFolder)) { - $_tool_item = Get-Item "$($_kit_path.InstallationFolder)\$tool.exe" -EA 0 - if (-not (Test-Path alias:\$tool) -and $_tool_item) { - Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global - return - } - } - } - } - foreach ($ver in ("KitsRoot81", "KitsRoot")) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver - if (-not $_kit_path) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver - } - - foreach ($kit in ("x64", "x86")) { - if ($_kit_path -and (Test-Path "$_kit_path\bin\$kit")) { - $_tool_item = Get-Item "$_kit_path\bin\$kit\$tool.exe" -EA 0 - if (-not (Test-Path alias:\$tool) -and $_tool_item) { - Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global - return - } - } - } - } -} - -function begin_sign_files { - param($files, $outdir, $approvers, $projectName, $projectUrl, $jobDescription, $jobKeywords, $certificates, [switch] $delaysigned) - - if ($files.Count -eq 0) { - return - } - - if ($delaysigned) { - # Ensure that all files are delay-signed - # "sn -q -v ..." is true if the assembly has strong name and skip verification - _find_sdk_tool "sn" - if (Test-Path alias:\sn) { - $not_delay_signed = $files | %{ gi $_.path } | ?{ sn -q -v $_ } - if ($not_delay_signed) { - Throw "Delay-signed check failed: $($not_delay_signed.Name -join ' -')" - } - } - } - - [Reflection.Assembly]::Load("CODESIGN.Submitter, Version=3.0.0.6, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null - [Reflection.Assembly]::Load("CODESIGN.PolicyManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null - - while ($True) { - try { - $job = [CODESIGN.Submitter.Job]::Initialize("codesign.gtm.microsoft.com", 9556, $True) - $job.Description = $jobDescription - $job.Keywords = $jobKeywords - - if ($certificates -match "authenticode") { - $job.SelectCertificate("10006") # Authenticode - } - if ($certificates -match "strongname") { - $job.SelectCertificate("67") # StrongName key - } - if ($certificates -match "opc") { - $job.SelectCertificate("160") # Microsoft OPC Publisher (VSIX) - } - - foreach ($approver in $approvers) { - $job.AddApprover($approver) - } - - foreach ($file in $files) { - $job.AddFile($file.path, $file.name, $projectUrl, [CODESIGN.JavaPermissionsTypeEnum]::None) - } - - $job.Send() - return @{job=$job; description=$jobDescription; filecount=$($files.Count); outdir=$outdir} - } catch [Exception] { - echo $_.Exception.Message - sleep 60 - } - } -} - -function end_sign_files { - param($jobs) - - if ($jobs.Count -eq 0) { - return - } - - foreach ($jobinfo in $jobs) { - $job = $jobinfo.job - if($job -eq $null) { - throw "jobinfo in unexpected format $jobinfo" - } - $filecount = $jobinfo.filecount - $outdir = $jobinfo.outdir - $activity = "Processing $($jobinfo.description) (Job ID $($job.JobID))" - $percent = 0 - $jobCompletionPath = $job.JobCompletionPath - - if([string]::IsNullOrWhiteSpace($jobCompletionPath)) { - throw "job.JobCompletionPath is not valid: $job.JobCompletionPath" - } - - do { - $files = dir $jobCompletionPath - Write-Progress -activity $activity -status "Waiting for completion: $jobCompletionPath" -percentcomplete $percent; - $percent = ($percent + 1) % 100 - sleep -seconds 5 - } while(-not $files -or $files.Count -ne $filecount); - - mkdir $outdir -EA 0 | Out-Null - Write-Progress -Activity $activity -Completed - - Write-Output "Copying from $jobCompletionPath to $outdir" - $retries = 9 - $delay = 2 - $copied = $null - while ($retries) { - try { - $copied = (Copy-Item -path $jobCompletionPath\* -dest $outdir -Force -PassThru) - break - } catch { - if ($retries -eq 0) { - break - } - Write-Warning "Failed to copy - retrying in $delay seconds ($retries tries remaining)" - Sleep -seconds $delay - --$retries - $delay += $delay - } - } - if (-not $copied) { - Throw "Failed to copy $jobCompletionPath to $outdir" - } else { - Write-Output "Copied $($copied.Count) files" - } - } -} - -function start_virus_scan { - param($description, $contact, $path) - - $xml = New-Object XML - $xml.LoadXml("AOC") - $xml.root.description = $description - $xml.root.contact = $contact - $xml.root.path = $path - - Invoke-WebRequest "http://vcs/process.asp" -Method Post -Body $xml -ContentType "text/xml" -UseDefaultCredentials -UseBasicParsing -} - -function check_signing { - param($outdir) - - _find_sdk_tool "signtool" - - $unsigned = @() - - $msis = gci $outdir\*.msi - foreach ($m in $msis) { - Write-Host "Checking signatures for $m" - & signtool verify /pa "$m" 2>&1 | Out-Null - if (-not $?) { - $unsigned += "$m" - } - - $dir = mkdir -fo "${env:TEMP}\msi_test" - & msiexec /q /a "$m" TARGETDIR="$dir" | Out-Null - - foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { - & signtool verify /pa "$f" 2>&1 | Out-Null - if (-not $?) { - $unsigned += "$m - $($f.Name)" - } - } - - rmdir -r -fo $dir - } - - Add-Type -assembly "System.IO.Compression.FileSystem" - $zips = gci $outdir\*.vsix - foreach ($m in $zips) { - Write-Host "Checking signatures for $m" - $dir = mkdir -fo "${env:TEMP}\msi_test" - [IO.Compression.ZipFile]::ExtractToDirectory($m, $dir) - - if (-not (Test-Path "$dir\package\services\digital-signature\xml-signature")) { - $unsigned += "$m" - } - - foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { - & signtool verify /pa "$f" 2>&1 | Out-Null - if (-not $?) { - $unsigned += "$m - $($f.Name)" - } - } - - rmdir -r -fo $dir - } - - if ($unsigned) { - throw "Following files have invalid signatures: -$(($unsigned | select -unique) -join ' -')" - } +function submit_symbols { + param($buildname, $buildid, $filetype, $sourcedir, $contacts) + + $request = ` + "BuildId=$buildid $filetype + BuildLabPhone=7058786 + BuildRemark=$buildname + ContactPeople=$contacts + Directory=$sourcedir + Project=TechnicalComputing + Recursive=yes + StatusMail=$contacts + UserName=$env:username" + + Write-Output "*** Symbol Submission Text *** +$request" + + $request | Out-File -Encoding ascii -FilePath request_$filetype.txt + \\symbols\tools\createrequest.cmd -i request_$filetype.txt -d .\SymSrvRequestLogs -c -s +} + +function _find_sdk_tool { + param($tool) + + $_tool_item = "" + foreach ($ver in ("v8.1A", "v8.0A")) { + foreach ($kit in ("WinSDK-NetFx40Tools-x64", "WinSDK-NetFx40Tools-x86", "WinSDK-NetFx40Tools")) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) + if (-not $_kit_path) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) + } + + if ($_kit_path -and (Test-Path $_kit_path.InstallationFolder)) { + $_tool_item = Get-Item "$($_kit_path.InstallationFolder)\$tool.exe" -EA 0 + if (-not (Test-Path alias:\$tool) -and $_tool_item) { + Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global + return + } + } + } + } + foreach ($ver in ("KitsRoot81", "KitsRoot")) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver + if (-not $_kit_path) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver + } + + foreach ($kit in ("x64", "x86")) { + if ($_kit_path -and (Test-Path "$_kit_path\bin\$kit")) { + $_tool_item = Get-Item "$_kit_path\bin\$kit\$tool.exe" -EA 0 + if (-not (Test-Path alias:\$tool) -and $_tool_item) { + Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global + return + } + } + } + } +} + +function begin_sign_files { + param($files, $outdir, $approvers, $projectName, $projectUrl, $jobDescription, $jobKeywords, $certificates, [switch] $delaysigned) + + if ($files.Count -eq 0) { + return + } + + if ($delaysigned) { + # Ensure that all files are delay-signed + # "sn -q -v ..." is true if the assembly has strong name and skip verification + _find_sdk_tool "sn" + if (Test-Path alias:\sn) { + $not_delay_signed = $files | %{ gi $_.path } | ?{ sn -q -v $_ } + if ($not_delay_signed) { + Throw "Delay-signed check failed: $($not_delay_signed.Name -join ' +')" + } + } + } + + [Reflection.Assembly]::Load("CODESIGN.Submitter, Version=3.0.0.6, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null + [Reflection.Assembly]::Load("CODESIGN.PolicyManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null + + while ($True) { + try { + $job = [CODESIGN.Submitter.Job]::Initialize("codesign.gtm.microsoft.com", 9556, $True) + $job.Description = $jobDescription + $job.Keywords = $jobKeywords + + if ($certificates -match "authenticode") { + $job.SelectCertificate("10006") # Authenticode + } + if ($certificates -match "strongname") { + $job.SelectCertificate("67") # StrongName key + } + if ($certificates -match "opc") { + $job.SelectCertificate("160") # Microsoft OPC Publisher (VSIX) + } + + foreach ($approver in $approvers) { + $job.AddApprover($approver) + } + + foreach ($file in $files) { + $job.AddFile($file.path, $file.name, $projectUrl, [CODESIGN.JavaPermissionsTypeEnum]::None) + } + + $job.Send() + return @{job=$job; description=$jobDescription; filecount=$($files.Count); outdir=$outdir} + } catch [Exception] { + echo $_.Exception.Message + sleep 60 + } + } +} + +function end_sign_files { + param($jobs) + + if ($jobs.Count -eq 0) { + return + } + + foreach ($jobinfo in $jobs) { + $job = $jobinfo.job + if($job -eq $null) { + throw "jobinfo in unexpected format $jobinfo" + } + $filecount = $jobinfo.filecount + $outdir = $jobinfo.outdir + $activity = "Processing $($jobinfo.description) (Job ID $($job.JobID))" + $percent = 0 + $jobCompletionPath = $job.JobCompletionPath + + if([string]::IsNullOrWhiteSpace($jobCompletionPath)) { + throw "job.JobCompletionPath is not valid: $job.JobCompletionPath" + } + + do { + $files = dir $jobCompletionPath + Write-Progress -activity $activity -status "Waiting for completion: $jobCompletionPath" -percentcomplete $percent; + $percent = ($percent + 1) % 100 + sleep -seconds 5 + } while(-not $files -or $files.Count -ne $filecount); + + mkdir $outdir -EA 0 | Out-Null + Write-Progress -Activity $activity -Completed + + Write-Output "Copying from $jobCompletionPath to $outdir" + $retries = 9 + $delay = 2 + $copied = $null + while ($retries) { + try { + $copied = (Copy-Item -path $jobCompletionPath\* -dest $outdir -Force -PassThru) + break + } catch { + if ($retries -eq 0) { + break + } + Write-Warning "Failed to copy - retrying in $delay seconds ($retries tries remaining)" + Sleep -seconds $delay + --$retries + $delay += $delay + } + } + if (-not $copied) { + Throw "Failed to copy $jobCompletionPath to $outdir" + } else { + Write-Output "Copied $($copied.Count) files" + } + } +} + +function start_virus_scan { + param($description, $contact, $path) + + $xml = New-Object XML + $xml.LoadXml("AOC") + $xml.root.description = $description + $xml.root.contact = $contact + $xml.root.path = $path + + Invoke-WebRequest "http://vcs/process.asp" -Method Post -Body $xml -ContentType "text/xml" -UseDefaultCredentials -UseBasicParsing +} + +function check_signing { + param($outdir) + + _find_sdk_tool "signtool" + + $unsigned = @() + + $msis = gci $outdir\*.msi + foreach ($m in $msis) { + Write-Host "Checking signatures for $m" + & signtool verify /pa "$m" 2>&1 | Out-Null + if (-not $?) { + $unsigned += "$m" + } + + $dir = mkdir -fo "${env:TEMP}\msi_test" + & msiexec /q /a "$m" TARGETDIR="$dir" | Out-Null + + foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { + & signtool verify /pa "$f" 2>&1 | Out-Null + if (-not $?) { + $unsigned += "$m - $($f.Name)" + } + } + + rmdir -r -fo $dir + } + + Add-Type -assembly "System.IO.Compression.FileSystem" + $zips = gci $outdir\*.vsix + foreach ($m in $zips) { + Write-Host "Checking signatures for $m" + $dir = mkdir -fo "${env:TEMP}\msi_test" + [IO.Compression.ZipFile]::ExtractToDirectory($m, $dir) + + if (-not (Test-Path "$dir\package\services\digital-signature\xml-signature")) { + $unsigned += "$m" + } + + foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { + & signtool verify /pa "$f" 2>&1 | Out-Null + if (-not $?) { + $unsigned += "$m - $($f.Name)" + } + } + + rmdir -r -fo $dir + } + + if ($unsigned) { + throw "Following files have invalid signatures: +$(($unsigned | select -unique) -join ' +')" + } } \ No newline at end of file diff --git a/Build/BuildReleaseMockHelpers.psm1 b/Build/BuildReleaseMockHelpers.psm1 index 7293654..abe9f97 100644 --- a/Build/BuildReleaseMockHelpers.psm1 +++ b/Build/BuildReleaseMockHelpers.psm1 @@ -1,277 +1,277 @@ -function submit_symbols { - param($buildname, $buildid, $filetype, $sourcedir, $contacts) - - Write-Debug "*** Symbol Submission Text *** - BuildId=$buildid $filetype - BuildLabPhone=7058786 - BuildRemark=$buildname - ContactPeople=$contacts - Directory=$sourcedir - Project=TechnicalComputing - Recursive=yes - StatusMail=$contacts - UserName=$env:username" -} - -function _find_sdk_tool { - param($tool) - - $_tool_item = "" - foreach ($ver in ("v8.1A", "v8.0A")) { - foreach ($kit in ("WinSDK-NetFx40Tools-x64", "WinSDK-NetFx40Tools-x86", "WinSDK-NetFx40Tools")) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) - if (-not $_kit_path) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) - } - - if ($_kit_path -and (Test-Path $_kit_path.InstallationFolder)) { - $_tool_item = Get-Item "$($_kit_path.InstallationFolder)\$tool.exe" -EA 0 - if (-not (Test-Path alias:\$tool) -and $_tool_item) { - Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global - } - } - } - } - foreach ($ver in ("KitsRoot81", "KitsRoot")) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver - if (-not $_kit_path) { - $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver - } - - foreach ($kit in ("x64", "x86")) { - if ($_kit_path -and (Test-Path "$_kit_path\bin\$kit")) { - $_tool_item = Get-Item "$_kit_path\bin\$kit\$tool.exe" -EA 0 - if (-not (Test-Path alias:\$tool) -and $_tool_item) { - Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global - return - } - } - } - } -} - -function begin_sign_files { - param($files, $outdir, $approvers, $projectName, $projectUrl, $jobDescription, $jobKeywords, $certificates, [switch] $delaysigned) - - if ($files.Count -eq 0) { - return - } - - if ($delaysigned) { - # Ensure that all files are delay-signed - # "sn -q -v ..." is true if the assembly has strong name and skip verification - _find_sdk_tool "sn" - if (Test-Path alias:\sn) { - $not_delay_signed = $files | %{ gi $_.path } | ?{ sn -q -v $_ } - if ($not_delay_signed) { - Throw "Delay-signed check failed: $($not_delay_signed.Name -join ' -') -You may need to skip strong name verification on this machine." - } - } - } - - [Reflection.Assembly]::Load("CODESIGN.Submitter, Version=3.0.0.6, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null - [Reflection.Assembly]::Load("CODESIGN.PolicyManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null - - $job = [CODESIGN.Submitter.Job]::Initialize("codesign.gtm.microsoft.com", 9556, $True) - $msg = "*** Signing Job Details *** -job.Description: $jobDescription -job.Keywords: $jobKeywords" - $job.Description = $jobDescription - $job.Keywords = $jobKeywords - - if ($certificates -match "authenticode") { - $msg = "$msg -job.SelectCertificate(10006)" - $job.SelectCertificate("10006") # Authenticode - } - if ($certificates -match "strongname") { - $msg = "$msg -job.SelectCertificate(67)" - $job.SelectCertificate("67") # StrongName key - } - if ($certificates -match "opc") { - $job.SelectCertificate("160") # Microsoft OPC Publisher (VSIX) - } - - foreach ($approver in $approvers) { - $msg = "$msg -job.AddApprover($approver)" - $job.AddApprover($approver) - } - - foreach ($file in $files) { - $msg = "$msg -job.AddFile($($file.path), $($file.name), $projectUrl, None)" - $job.AddFile($file.path, $file.name, $projectUrl, [CODESIGN.JavaPermissionsTypeEnum]::None) - } - - $msg = "$msg -Returning @{filecount=$($files.Count); outdir=$outdir}" - Write-Debug $msg - - $uniqueJobFolderID = ((Get-Date -format "yyyyMMdd-HHmmss").ToString() + "-" + (Get-Date).Millisecond.ToString()) - - $folder = ((Get-Item $($files[0].path)).DirectoryName.ToString() + "\MockSigned") - - $mockJob = New-Object PSObject - $mockJob | Add-Member NoteProperty JobID $uniqueJobFolderID - $mockJob | Add-Member NoteProperty JobMockFolder $folder - $mockJob | Add-Member NoteProperty JobCompletionPath $folder\$uniqueJobFolderID - - $mockFolderPath = $mockJob.JobCompletionPath - mkdir $mockFolderPath -EA 0 | Out-Null - - foreach($file in $files) { - $destPath = "$($mockFolderPath)\$($fileInfo.Name)" - copy -path $($file.path) -dest $destPath - if (-not $?) { - Write-Output "Failed to copy $($file.path) to $destPath" - } - } - - return @{rjob=$job; job=$mockJob; description=$jobDescription; filecount=$($files.Count); outdir=$outdir} -} - -function end_sign_files { - param($jobs) - - if ($jobs.Count -eq 0) { - return - } - - foreach ($jobinfo in $jobs) { - $job = $jobinfo.job - if($job -eq $null) { - throw "jobinfo in unexpected format $jobinfo" - } - $filecount = $jobinfo.filecount - $outdir = $jobinfo.outdir - $activity = "Processing $($jobinfo.description) (Job ID $($job.JobID))" - $percent = 0 - $jobCompletionPath = $job.JobCompletionPath - - if([string]::IsNullOrWhiteSpace($jobCompletionPath)) { - throw "job.JobCompletionPath is not valid: $($job.JobCompletionPath)" - } - - do { - $files = @() - Write-Progress -activity $activity -status "Waiting for completion: $jobCompletionPath" -percentcomplete $percent; - $percent = ($percent + 1) % 100 - if ($percent -eq 90) { - $files = dir $jobCompletionPath - } - sleep -Milliseconds 50 - } while(-not $files -or $files.Count -ne $filecount); - - mkdir $outdir -EA 0 | Out-Null - Write-Progress -Activity $activity -Completed - - Write-Output "Copying from $jobCompletionPath to $outdir" - $retries = 9 - $delay = 2 - $copied = $null - while ($retries) { - try { - $copied = (Copy-Item -path $jobCompletionPath\* -dest $outdir -Force -PassThru) - break - } catch { - if ($retries -eq 0) { - break - } - Write-Warning "Failed to copy - retrying in $delay seconds ($retries tries remaining)" - Sleep -seconds $delay - --$retries - $delay += $delay - } - } - if (-not $copied) { - Throw "Failed to copy $jobCompletionPath to $outdir" - } else { - Write-Output "Copied $($copied.Count) files" - } - - #Get rid of the MockSigned directory - Remove-Item -Recurse $jobCompletionPath\* - Remove-Item -Recurse $jobCompletionPath - - if((Get-Item $($job.JobMockFolder)).GetDirectories().Count -eq 0) { - Remove-Item -Recurse $($job.JobMockFolder) - } - } -} - -function start_virus_scan { - param($description, $contact, $path) - - $xml = New-Object XML - $xml.LoadXml("AOC") - $xml.root.description = $description - $xml.root.contact = $contact - $xml.root.path = $path - - Write-Debug "Posting to http://vcs/process.asp: -$($xml.OuterXml)" -} - -function check_signing { - param($outdir) - - _find_sdk_tool "signtool" - - $unsigned = @() - - $msis = gci $outdir\*.msi - foreach ($m in $msis) { - Write-Host "Checking signatures for $m" - & signtool verify /pa "$m" 2>&1 | Out-Null - # All files should be unsigned - if ($?) { - $unsigned += "$m" - } - - $dir = mkdir -fo "${env:TEMP}\msi_test" - & msiexec /q /a "$m" TARGETDIR="$dir" | Out-Null - - foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { - & signtool verify /pa "$f" 2>&1 | Out-Null - # All files should be unsigned - if ($?) { - $unsigned += "$m - $($f.Name)" - } - } - - rmdir -r -fo $dir - } - - Add-Type -assembly "System.IO.Compression.FileSystem" - $zips = gci $outdir\*.vsix - foreach ($m in $zips) { - Write-Host "Checking signatures for $m" - $dir = mkdir -fo "${env:TEMP}\msi_test" - [IO.Compression.ZipFile]::ExtractToDirectory($m, $dir) - - # All files should be unsigned - if ((Test-Path "$dir\package\services\digital-signature\xml-signature")) { - $unsigned += "$m" - } - - foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { - & signtool verify /pa "$f" 2>&1 | Out-Null - # All files should be unsigned - if ($?) { - $unsigned += "$m - $($f.Name)" - } - } - - rmdir -r -fo $dir - } - - if ($unsigned) { - throw "Following files have invalid signatures: -$(($unsigned | select -unique) -join ' -')" - } -} +function submit_symbols { + param($buildname, $buildid, $filetype, $sourcedir, $contacts) + + Write-Debug "*** Symbol Submission Text *** + BuildId=$buildid $filetype + BuildLabPhone=7058786 + BuildRemark=$buildname + ContactPeople=$contacts + Directory=$sourcedir + Project=TechnicalComputing + Recursive=yes + StatusMail=$contacts + UserName=$env:username" +} + +function _find_sdk_tool { + param($tool) + + $_tool_item = "" + foreach ($ver in ("v8.1A", "v8.0A")) { + foreach ($kit in ("WinSDK-NetFx40Tools-x64", "WinSDK-NetFx40Tools-x86", "WinSDK-NetFx40Tools")) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) + if (-not $_kit_path) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\$ver\$kit" -EA 0) + } + + if ($_kit_path -and (Test-Path $_kit_path.InstallationFolder)) { + $_tool_item = Get-Item "$($_kit_path.InstallationFolder)\$tool.exe" -EA 0 + if (-not (Test-Path alias:\$tool) -and $_tool_item) { + Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global + } + } + } + } + foreach ($ver in ("KitsRoot81", "KitsRoot")) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver + if (-not $_kit_path) { + $_kit_path = (Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots" -Name $ver -EA 0).$ver + } + + foreach ($kit in ("x64", "x86")) { + if ($_kit_path -and (Test-Path "$_kit_path\bin\$kit")) { + $_tool_item = Get-Item "$_kit_path\bin\$kit\$tool.exe" -EA 0 + if (-not (Test-Path alias:\$tool) -and $_tool_item) { + Set-Alias -Name $tool -Value $_tool_item.FullName -Scope Global + return + } + } + } + } +} + +function begin_sign_files { + param($files, $outdir, $approvers, $projectName, $projectUrl, $jobDescription, $jobKeywords, $certificates, [switch] $delaysigned) + + if ($files.Count -eq 0) { + return + } + + if ($delaysigned) { + # Ensure that all files are delay-signed + # "sn -q -v ..." is true if the assembly has strong name and skip verification + _find_sdk_tool "sn" + if (Test-Path alias:\sn) { + $not_delay_signed = $files | %{ gi $_.path } | ?{ sn -q -v $_ } + if ($not_delay_signed) { + Throw "Delay-signed check failed: $($not_delay_signed.Name -join ' +') +You may need to skip strong name verification on this machine." + } + } + } + + [Reflection.Assembly]::Load("CODESIGN.Submitter, Version=3.0.0.6, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null + [Reflection.Assembly]::Load("CODESIGN.PolicyManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d8252bd1272440d, processorArchitecture=MSIL") | Out-Null + + $job = [CODESIGN.Submitter.Job]::Initialize("codesign.gtm.microsoft.com", 9556, $True) + $msg = "*** Signing Job Details *** +job.Description: $jobDescription +job.Keywords: $jobKeywords" + $job.Description = $jobDescription + $job.Keywords = $jobKeywords + + if ($certificates -match "authenticode") { + $msg = "$msg +job.SelectCertificate(10006)" + $job.SelectCertificate("10006") # Authenticode + } + if ($certificates -match "strongname") { + $msg = "$msg +job.SelectCertificate(67)" + $job.SelectCertificate("67") # StrongName key + } + if ($certificates -match "opc") { + $job.SelectCertificate("160") # Microsoft OPC Publisher (VSIX) + } + + foreach ($approver in $approvers) { + $msg = "$msg +job.AddApprover($approver)" + $job.AddApprover($approver) + } + + foreach ($file in $files) { + $msg = "$msg +job.AddFile($($file.path), $($file.name), $projectUrl, None)" + $job.AddFile($file.path, $file.name, $projectUrl, [CODESIGN.JavaPermissionsTypeEnum]::None) + } + + $msg = "$msg +Returning @{filecount=$($files.Count); outdir=$outdir}" + Write-Debug $msg + + $uniqueJobFolderID = ((Get-Date -format "yyyyMMdd-HHmmss").ToString() + "-" + (Get-Date).Millisecond.ToString()) + + $folder = ((Get-Item $($files[0].path)).DirectoryName.ToString() + "\MockSigned") + + $mockJob = New-Object PSObject + $mockJob | Add-Member NoteProperty JobID $uniqueJobFolderID + $mockJob | Add-Member NoteProperty JobMockFolder $folder + $mockJob | Add-Member NoteProperty JobCompletionPath $folder\$uniqueJobFolderID + + $mockFolderPath = $mockJob.JobCompletionPath + mkdir $mockFolderPath -EA 0 | Out-Null + + foreach($file in $files) { + $destPath = "$($mockFolderPath)\$($fileInfo.Name)" + copy -path $($file.path) -dest $destPath + if (-not $?) { + Write-Output "Failed to copy $($file.path) to $destPath" + } + } + + return @{rjob=$job; job=$mockJob; description=$jobDescription; filecount=$($files.Count); outdir=$outdir} +} + +function end_sign_files { + param($jobs) + + if ($jobs.Count -eq 0) { + return + } + + foreach ($jobinfo in $jobs) { + $job = $jobinfo.job + if($job -eq $null) { + throw "jobinfo in unexpected format $jobinfo" + } + $filecount = $jobinfo.filecount + $outdir = $jobinfo.outdir + $activity = "Processing $($jobinfo.description) (Job ID $($job.JobID))" + $percent = 0 + $jobCompletionPath = $job.JobCompletionPath + + if([string]::IsNullOrWhiteSpace($jobCompletionPath)) { + throw "job.JobCompletionPath is not valid: $($job.JobCompletionPath)" + } + + do { + $files = @() + Write-Progress -activity $activity -status "Waiting for completion: $jobCompletionPath" -percentcomplete $percent; + $percent = ($percent + 1) % 100 + if ($percent -eq 90) { + $files = dir $jobCompletionPath + } + sleep -Milliseconds 50 + } while(-not $files -or $files.Count -ne $filecount); + + mkdir $outdir -EA 0 | Out-Null + Write-Progress -Activity $activity -Completed + + Write-Output "Copying from $jobCompletionPath to $outdir" + $retries = 9 + $delay = 2 + $copied = $null + while ($retries) { + try { + $copied = (Copy-Item -path $jobCompletionPath\* -dest $outdir -Force -PassThru) + break + } catch { + if ($retries -eq 0) { + break + } + Write-Warning "Failed to copy - retrying in $delay seconds ($retries tries remaining)" + Sleep -seconds $delay + --$retries + $delay += $delay + } + } + if (-not $copied) { + Throw "Failed to copy $jobCompletionPath to $outdir" + } else { + Write-Output "Copied $($copied.Count) files" + } + + #Get rid of the MockSigned directory + Remove-Item -Recurse $jobCompletionPath\* + Remove-Item -Recurse $jobCompletionPath + + if((Get-Item $($job.JobMockFolder)).GetDirectories().Count -eq 0) { + Remove-Item -Recurse $($job.JobMockFolder) + } + } +} + +function start_virus_scan { + param($description, $contact, $path) + + $xml = New-Object XML + $xml.LoadXml("AOC") + $xml.root.description = $description + $xml.root.contact = $contact + $xml.root.path = $path + + Write-Debug "Posting to http://vcs/process.asp: +$($xml.OuterXml)" +} + +function check_signing { + param($outdir) + + _find_sdk_tool "signtool" + + $unsigned = @() + + $msis = gci $outdir\*.msi + foreach ($m in $msis) { + Write-Host "Checking signatures for $m" + & signtool verify /pa "$m" 2>&1 | Out-Null + # All files should be unsigned + if ($?) { + $unsigned += "$m" + } + + $dir = mkdir -fo "${env:TEMP}\msi_test" + & msiexec /q /a "$m" TARGETDIR="$dir" | Out-Null + + foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { + & signtool verify /pa "$f" 2>&1 | Out-Null + # All files should be unsigned + if ($?) { + $unsigned += "$m - $($f.Name)" + } + } + + rmdir -r -fo $dir + } + + Add-Type -assembly "System.IO.Compression.FileSystem" + $zips = gci $outdir\*.vsix + foreach ($m in $zips) { + Write-Host "Checking signatures for $m" + $dir = mkdir -fo "${env:TEMP}\msi_test" + [IO.Compression.ZipFile]::ExtractToDirectory($m, $dir) + + # All files should be unsigned + if ((Test-Path "$dir\package\services\digital-signature\xml-signature")) { + $unsigned += "$m" + } + + foreach ($f in (gci $dir\*.exe, $dir\*.dll -r)) { + & signtool verify /pa "$f" 2>&1 | Out-Null + # All files should be unsigned + if ($?) { + $unsigned += "$m - $($f.Name)" + } + } + + rmdir -r -fo $dir + } + + if ($unsigned) { + throw "Following files have invalid signatures: +$(($unsigned | select -unique) -join ' +')" + } +} diff --git a/Build/GetWix.ps1 b/Build/GetWix.ps1 deleted file mode 100644 index 2834c65..0000000 --- a/Build/GetWix.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -function Get-Wix { - param($target) - - Write-Output "Downloading Wix to $target" - - $file = [IO.Path]::GetTempFileName() - Write-Output " - temporary storage: $file" - - Invoke-WebRequest "https://wix.codeplex.com/downloads/get/1421697" -UseBasicParsing -OutFile $file - - [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null - [System.IO.Compression.ZipFile]::ExtractToDirectory($file, $target) - - del $file -} diff --git a/Build/NuGet.exe b/Build/NuGet.exe new file mode 100644 index 0000000..324daa8 Binary files /dev/null and b/Build/NuGet.exe differ diff --git a/BuildVSTestHost.ps1 b/BuildVSTestHost.ps1 index 0f523fe..3a166cd 100644 --- a/BuildVSTestHost.ps1 +++ b/BuildVSTestHost.ps1 @@ -18,16 +18,15 @@ if (-not $outdir) { } Write-Output "Writing output MSIs to $outdir" +pushd (Join-Path $projectDir Installer) +..\Build\nuget.exe restore packages.config -PackagesDirectory (Join-Path $projectDir packages) +popd + $originalbuildtarget = $buildtarget if ($sign -or $mocksign) { $buildtarget = "BuildVSTestHost" } -if (-not (Test-Path $projectDir\Build\Wix\wix.targets)) { - Import-Module $projectDir\Build\GetWix.ps1 -Force - Get-Wix (mkdir -Force "$projectDir\Build\Wix") -EA Stop -} - msbuild $projectDir\Installer\Installer.wixproj ` /fl /flp:logfile="$projectDir\VSTestHost.build.log" ` /v:m ` diff --git a/DeveloperGuide.md b/DeveloperGuide.md index 2c8952e..3d77774 100644 --- a/DeveloperGuide.md +++ b/DeveloperGuide.md @@ -83,7 +83,7 @@ follows: | VSApplication | The registry key name, like "VisualStudio" or "WDExpress" | | VSExecutable | The executable name, like "devenv" or "wdexpress" | | VSVersion | The version number, like "12.0" or "14.0" | -| VSHive [optional] | The hive name, like "Exp" | +| VSHive | The hive name, like "Exp" or "Default" | | VSLaunchTimeoutInSeconds [opt] | The number of seconds to wait for launch | | VSDebugMixedMode | True to use mixed-mode debugging for tests | | ScreenCapture [opt] | Relative path to capture screenshots to | diff --git a/DisableSkipVerification.reg b/DisableSkipVerification.reg index ff25f0a..c99c0bf 100644 --- a/DisableSkipVerification.reg +++ b/DisableSkipVerification.reg @@ -1,10 +1,10 @@ -Windows Registry Editor Version 5.00 - -[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] -[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] +Windows Registry Editor Version 5.00 + +[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] +[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] diff --git a/DisableVSTestHost12.0.reg b/DisableVSTestHost12.0.reg index 6256e19..53fa451 100644 --- a/DisableVSTestHost12.0.reg +++ b/DisableVSTestHost12.0.reg @@ -1,6 +1,6 @@ -Windows Registry Editor Version 5.00 - -[-HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] -"VSTestHost"=- - +Windows Registry Editor Version 5.00 + +[-HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] +"VSTestHost"=- + diff --git a/DisableVSTestHost14.0.reg b/DisableVSTestHost14.0.reg index 7a81668..b9f0b80 100644 --- a/DisableVSTestHost14.0.reg +++ b/DisableVSTestHost14.0.reg @@ -1,6 +1,6 @@ -Windows Registry Editor Version 5.00 - -[-HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] -"VSTestHost"=- - +Windows Registry Editor Version 5.00 + +[-HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] +"VSTestHost"=- + diff --git a/EnableSkipVerification.reg b/EnableSkipVerification.reg index 878908d..7a0a11a 100644 --- a/EnableSkipVerification.reg +++ b/EnableSkipVerification.reg @@ -1,10 +1,10 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] -[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.10.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.11.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.12.0,B03F5F7F11D50A3A] +[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\Microsoft.VisualStudioTools.VSTestHost.14.0,B03F5F7F11D50A3A] diff --git a/EnableVSTestHost12.0.reg b/EnableVSTestHost12.0.reg index ce67acc..e96baac 100644 --- a/EnableVSTestHost12.0.reg +++ b/EnableVSTestHost12.0.reg @@ -1,10 +1,10 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] -"Type"="Microsoft.VisualStudioTools.VSTestHost.TesterTestAdapter, Microsoft.VisualStudioTools.VSTestHost.12.0, Version=12.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" -"EditorType"="Microsoft.VisualStudioTools.VSTestHost.TesterTestControl, Microsoft.VisualStudioTools.VSTestHost.12.0, Version=12.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost\SupportedTestTypes] -"{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}"="Unit Test" -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] -"VSTestHost"="VS Test Host Adapter" - +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] +"Type"="Microsoft.VisualStudioTools.VSTestHost.TesterTestAdapter, Microsoft.VisualStudioTools.VSTestHost.12.0, Version=12.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" +"EditorType"="Microsoft.VisualStudioTools.VSTestHost.TesterTestControl, Microsoft.VisualStudioTools.VSTestHost.12.0, Version=12.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost\SupportedTestTypes] +"{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}"="Unit Test" +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\12.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] +"VSTestHost"="VS Test Host Adapter" + diff --git a/EnableVSTestHost14.0.reg b/EnableVSTestHost14.0.reg index 2785ffa..3ef15bd 100644 --- a/EnableVSTestHost14.0.reg +++ b/EnableVSTestHost14.0.reg @@ -1,10 +1,10 @@ -Windows Registry Editor Version 5.00 - -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] -"Type"="Microsoft.VisualStudioTools.VSTestHost.TesterTestAdapter, Microsoft.VisualStudioTools.VSTestHost.14.0, Version=14.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" -"EditorType"="Microsoft.VisualStudioTools.VSTestHost.TesterTestControl, Microsoft.VisualStudioTools.VSTestHost.14.0, Version=14.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost\SupportedTestTypes] -"{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}"="Unit Test" -[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] -"VSTestHost"="VS Test Host Adapter" - +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost] +"Type"="Microsoft.VisualStudioTools.VSTestHost.TesterTestAdapter, Microsoft.VisualStudioTools.VSTestHost.14.0, Version=14.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" +"EditorType"="Microsoft.VisualStudioTools.VSTestHost.TesterTestControl, Microsoft.VisualStudioTools.VSTestHost.14.0, Version=14.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\HostAdapters\VSTestHost\SupportedTestTypes] +"{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}"="Unit Test" +[HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\VisualStudio\14.0\EnterpriseTools\QualityTools\TestTypes\{13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b}\SupportedHostAdapters] +"VSTestHost"="VS Test Host Adapter" + diff --git a/Installer/Installer.wixproj b/Installer/Installer.wixproj index eb497f8..7242818 100644 --- a/Installer/Installer.wixproj +++ b/Installer/Installer.wixproj @@ -1,5 +1,6 @@  + Debug x86 @@ -9,8 +10,6 @@ VSTestHost Package false - $(MSBuildThisFileDirectory)\..\Build\Wix - $(WixInstallPath)\Wix.targets Build 11;12;14 @@ -79,4 +78,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/Installer/Product.wxs b/Installer/Product.wxs index 1e2b3de..c5d1b08 100644 --- a/Installer/Product.wxs +++ b/Installer/Product.wxs @@ -3,7 +3,7 @@ diff --git a/Installer/packages.config b/Installer/packages.config new file mode 100644 index 0000000..ff1106d --- /dev/null +++ b/Installer/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3490170..6d2473b 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ These settings should be specified in a `.testsettings` file or with the `TestPr | VSApplication | The registry key name | "VisualStudio", "WDExpress", "VWDExpress", "Mock" | | VSExecutable | The executable name | "devenv", "wdexpress", "vwdexpress" | | VSVersion | The version number | "11.0", "12.0", "14.0" or blank (match tester) | -| VSHive | The hive name | "Exp" or blank | +| VSHive | The hive name | "Exp" or "Default" | | VSLaunchTimeoutInSeconds | The number of seconds to wait for launch | Any number, or blank (30s) | | VSDebugMixedMode | Use native debugging for tests | "True", "False" or blank | | ScreenCapture | Directory to capture screenshots into | Blank (do not capture) or a relative path | diff --git a/VSTestHost/Resources.Designer.cs b/VSTestHost/Resources.Designer.cs index 6e76fff..56e7827 100644 --- a/VSTestHost/Resources.Designer.cs +++ b/VSTestHost/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.0 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -191,6 +191,15 @@ internal static string VSFailedToLaunch { } } + /// + /// Looks up a localized string similar to Launching {0}: "...\Microsoft Visual Studio {2}\Common7\IDE\{1}{3}". + /// + internal static string VSLaunchMessage { + get { + return ResourceManager.GetString("VSLaunchMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Visual Studio failed to start within {0} seconds.. /// @@ -199,5 +208,14 @@ internal static string VSLaunchTimeout { return ResourceManager.GetString("VSLaunchTimeout", resourceCulture); } } + + /// + /// Looks up a localized string similar to Reusing {0}: "...\Microsoft Visual Studio {2}\Common7\IDE\{1}{3}". + /// + internal static string VSReuseMessage { + get { + return ResourceManager.GetString("VSReuseMessage", resourceCulture); + } + } } } diff --git a/VSTestHost/Resources.resx b/VSTestHost/Resources.resx index 52f76d4..b50f9b3 100644 --- a/VSTestHost/Resources.resx +++ b/VSTestHost/Resources.resx @@ -165,7 +165,13 @@ Failed to launch {1} ({0}, {2}{3}) application, executable, version, hive + + Launching {0}: "...\Microsoft Visual Studio {2}\Common7\IDE\{1}{3}" + Visual Studio failed to start within {0} seconds. + + Reusing {0}: "...\Microsoft Visual Studio {2}\Common7\IDE\{1}{3}" + \ No newline at end of file diff --git a/VSTestHost/ScreenRecorder.cs b/VSTestHost/ScreenRecorder.cs index db9d36d..6f04e65 100644 --- a/VSTestHost/ScreenRecorder.cs +++ b/VSTestHost/ScreenRecorder.cs @@ -12,246 +12,246 @@ * * ***************************************************************************/ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using System.Threading; -using System.Windows.Forms; -using Microsoft.VisualStudioTools.VSTestHost.Internal; - -namespace Microsoft.VisualStudioTools.VSTestHost { - sealed class ScreenRecorder : IDisposable { - private readonly System.Threading.Timer _timer; - private readonly DirectoryInfo _output; - private Bitmap _latestImage; - private DateTime _latestImageTime; - private TimeSpan _interval; - private bool _isDisposed = false; - - public ScreenRecorder(string outputPath) { - _timer = new System.Threading.Timer(Timer_Callback); - _output = Directory.CreateDirectory(outputPath); - } - - public void Dispose() { - if (!_isDisposed) { - _isDisposed = true; - _timer.Dispose(); - - var latestImage = _latestImage; - _latestImage = null; - if (latestImage != null) { - latestImage.Dispose(); - } - } - } - - public string Failure { get; private set; } - - public TimeSpan Interval { - get { - return _interval; - } - set { - _interval = value; - try { - _timer.Change((int)_interval.TotalMilliseconds, -1); - } catch (ObjectDisposedException) { - } - } - } - - private void Timer_Callback(object state) { - if (_isDisposed) { - return; - } - - try { - NextCapture(); - } catch (Exception ex) { - if (ex is OutOfMemoryException || ex is ThreadAbortException || ex is AccessViolationException) { - throw; - } - Failure = ex.ToString(); - } - } - - private void NextCapture() { - var bmp = Capture(Screen.AllScreens); - var time = DateTime.Now; - - var lastImage = _latestImage; - if (!AreSame(lastImage, bmp)) { - _latestImage = bmp; - _latestImageTime = time; - if (lastImage != null) { - lastImage.Dispose(); - } - - var nameFormat = time.ToString("s").Replace(":", "") + "{0}.png"; - using (var stream = OpenUniquelyNamedFile(_output.FullName, nameFormat)) { - bmp.Save(stream, ImageFormat.Png); - } - } else { - bmp.Dispose(); - } - - try { - _timer.Change((int)Interval.TotalMilliseconds, -1); - } catch (ObjectDisposedException) { - } - } - - - - private static Stream OpenUniquelyNamedFile(string directory, string format) { - string path = format; - try { - path = Path.Combine(directory, string.Format(format, "")); - return new FileStream( - path, - FileMode.CreateNew, - FileAccess.Write, - FileShare.Read - ); - } catch (IOException) { - } catch (UnauthorizedAccessException) { - } catch (NotSupportedException ex) { - throw new NotSupportedException(path, ex); - } - - // Try with an additional index - for (int i = 0; i < 0x100; ++i) { - try { - path = Path.Combine(directory, string.Format(format, string.Format("_{0}", i))); - return new FileStream( - path, - FileMode.CreateNew, - FileAccess.Write, - FileShare.Read - ); - } catch (IOException) { - } catch (UnauthorizedAccessException) { - } catch (NotSupportedException ex) { - throw new NotSupportedException(path, ex); - } - } - - // If we can't find an index, try a guid. If we still can't create - // the file, let the exception out so the user hears about it. - try { - path = Path.Combine(directory, string.Format(format, string.Format("_{0:N}", Guid.NewGuid()))); - return new FileStream( - path, - FileMode.CreateNew, - FileAccess.Write, - FileShare.Read - ); - } catch (NotSupportedException ex) { - throw new NotSupportedException(path, ex); - } - } - - private static Bitmap Capture(IList screens) { - if (screens.Count == 0) { - return null; - } - - Rectangle bounds = GetScreensBounds(screens); - - var bmp = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); - try { - using (var g = Graphics.FromImage(bmp)) { - g.Clear(Color.Black); - foreach (var s in screens) { - var d = s.Bounds.Location; - d.Offset(-bounds.X, -bounds.Y); - if (d.X < 0 || d.Y < 0) { - throw new InvalidOperationException(Resources.InvalidScreenBounds); - } - g.CopyFromScreen(s.Bounds.Location, d, s.Bounds.Size); - } - } - - var res = bmp; - bmp = null; - return res; - } finally { - if (bmp != null) { - bmp.Dispose(); - } - } - } - - private static Rectangle GetScreensBounds(IList screens) { - var bounds = screens[0].Bounds; - foreach (var s in screens.Skip(1)) { - if (s.Bounds.X < bounds.X) { - bounds.X = s.Bounds.X; - } - if (s.Bounds.Y < bounds.Y) { - bounds.Y = s.Bounds.Y; - } - if (s.Bounds.Right > bounds.Right) { - bounds.Width = s.Bounds.Right - bounds.Left; - if (bounds.Right != s.Bounds.Right) { - throw new InvalidOperationException(Resources.InvalidScreenBounds); - } - } - if (s.Bounds.Bottom > bounds.Bottom) { - bounds.Height = s.Bounds.Bottom - bounds.Top; - if (bounds.Bottom != s.Bounds.Bottom) { - throw new InvalidOperationException(Resources.InvalidScreenBounds); - } - } - } - - return bounds; - } - - private static unsafe bool AreSame(Bitmap x, Bitmap y) { - if (x == null || y == null) { - return x == null && y == null; - } - if (x.Width != y.Width || x.Height != y.Height) { - return false; - } - - var bounds = new Rectangle(Point.Empty, x.Size); - BitmapData bdX = null, bdY = null; - try { - bdX = x.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - bdY = y.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - var pX = (UInt32*)bdX.Scan0.ToPointer(); - var pY = (UInt32*)bdY.Scan0.ToPointer(); - int count = bdX.Width * bdX.Height; - if (count != bdY.Width * bdY.Height) { - // Should have already returned earlier in this case - Debug.Fail("Bitmap sizes must match"); - return false; - } - for (; count > 0; --count) { - if (*pX != *pY) { - return false; - } - pX += 1; - pY += 1; - } - - return true; - } finally { - if (bdX != null) { - x.UnlockBits(bdX); - } - if (bdY != null) { - y.UnlockBits(bdY); - } - } - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using Microsoft.VisualStudioTools.VSTestHost.Internal; + +namespace Microsoft.VisualStudioTools.VSTestHost { + sealed class ScreenRecorder : IDisposable { + private readonly System.Threading.Timer _timer; + private readonly DirectoryInfo _output; + private Bitmap _latestImage; + private DateTime _latestImageTime; + private TimeSpan _interval; + private bool _isDisposed = false; + + public ScreenRecorder(string outputPath) { + _timer = new System.Threading.Timer(Timer_Callback); + _output = Directory.CreateDirectory(outputPath); + } + + public void Dispose() { + if (!_isDisposed) { + _isDisposed = true; + _timer.Dispose(); + + var latestImage = _latestImage; + _latestImage = null; + if (latestImage != null) { + latestImage.Dispose(); + } + } + } + + public string Failure { get; private set; } + + public TimeSpan Interval { + get { + return _interval; + } + set { + _interval = value; + try { + _timer.Change((int)_interval.TotalMilliseconds, -1); + } catch (ObjectDisposedException) { + } + } + } + + private void Timer_Callback(object state) { + if (_isDisposed) { + return; + } + + try { + NextCapture(); + } catch (Exception ex) { + if (ex is OutOfMemoryException || ex is ThreadAbortException || ex is AccessViolationException) { + throw; + } + Failure = ex.ToString(); + } + } + + private void NextCapture() { + var bmp = Capture(Screen.AllScreens); + var time = DateTime.Now; + + var lastImage = _latestImage; + if (!AreSame(lastImage, bmp)) { + _latestImage = bmp; + _latestImageTime = time; + if (lastImage != null) { + lastImage.Dispose(); + } + + var nameFormat = time.ToString("s").Replace(":", "") + "{0}.png"; + using (var stream = OpenUniquelyNamedFile(_output.FullName, nameFormat)) { + bmp.Save(stream, ImageFormat.Png); + } + } else { + bmp.Dispose(); + } + + try { + _timer.Change((int)Interval.TotalMilliseconds, -1); + } catch (ObjectDisposedException) { + } + } + + + + private static Stream OpenUniquelyNamedFile(string directory, string format) { + string path = format; + try { + path = Path.Combine(directory, string.Format(format, "")); + return new FileStream( + path, + FileMode.CreateNew, + FileAccess.Write, + FileShare.Read + ); + } catch (IOException) { + } catch (UnauthorizedAccessException) { + } catch (NotSupportedException ex) { + throw new NotSupportedException(path, ex); + } + + // Try with an additional index + for (int i = 0; i < 0x100; ++i) { + try { + path = Path.Combine(directory, string.Format(format, string.Format("_{0}", i))); + return new FileStream( + path, + FileMode.CreateNew, + FileAccess.Write, + FileShare.Read + ); + } catch (IOException) { + } catch (UnauthorizedAccessException) { + } catch (NotSupportedException ex) { + throw new NotSupportedException(path, ex); + } + } + + // If we can't find an index, try a guid. If we still can't create + // the file, let the exception out so the user hears about it. + try { + path = Path.Combine(directory, string.Format(format, string.Format("_{0:N}", Guid.NewGuid()))); + return new FileStream( + path, + FileMode.CreateNew, + FileAccess.Write, + FileShare.Read + ); + } catch (NotSupportedException ex) { + throw new NotSupportedException(path, ex); + } + } + + private static Bitmap Capture(IList screens) { + if (screens.Count == 0) { + return null; + } + + Rectangle bounds = GetScreensBounds(screens); + + var bmp = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); + try { + using (var g = Graphics.FromImage(bmp)) { + g.Clear(Color.Black); + foreach (var s in screens) { + var d = s.Bounds.Location; + d.Offset(-bounds.X, -bounds.Y); + if (d.X < 0 || d.Y < 0) { + throw new InvalidOperationException(Resources.InvalidScreenBounds); + } + g.CopyFromScreen(s.Bounds.Location, d, s.Bounds.Size); + } + } + + var res = bmp; + bmp = null; + return res; + } finally { + if (bmp != null) { + bmp.Dispose(); + } + } + } + + private static Rectangle GetScreensBounds(IList screens) { + var bounds = screens[0].Bounds; + foreach (var s in screens.Skip(1)) { + if (s.Bounds.X < bounds.X) { + bounds.X = s.Bounds.X; + } + if (s.Bounds.Y < bounds.Y) { + bounds.Y = s.Bounds.Y; + } + if (s.Bounds.Right > bounds.Right) { + bounds.Width = s.Bounds.Right - bounds.Left; + if (bounds.Right != s.Bounds.Right) { + throw new InvalidOperationException(Resources.InvalidScreenBounds); + } + } + if (s.Bounds.Bottom > bounds.Bottom) { + bounds.Height = s.Bounds.Bottom - bounds.Top; + if (bounds.Bottom != s.Bounds.Bottom) { + throw new InvalidOperationException(Resources.InvalidScreenBounds); + } + } + } + + return bounds; + } + + private static unsafe bool AreSame(Bitmap x, Bitmap y) { + if (x == null || y == null) { + return x == null && y == null; + } + if (x.Width != y.Width || x.Height != y.Height) { + return false; + } + + var bounds = new Rectangle(Point.Empty, x.Size); + BitmapData bdX = null, bdY = null; + try { + bdX = x.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + bdY = y.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + var pX = (UInt32*)bdX.Scan0.ToPointer(); + var pY = (UInt32*)bdY.Scan0.ToPointer(); + int count = bdX.Width * bdX.Height; + if (count != bdY.Width * bdY.Height) { + // Should have already returned earlier in this case + Debug.Fail("Bitmap sizes must match"); + return false; + } + for (; count > 0; --count) { + if (*pX != *pY) { + return false; + } + pX += 1; + pY += 1; + } + + return true; + } finally { + if (bdX != null) { + x.UnlockBits(bdX); + } + if (bdY != null) { + y.UnlockBits(bdY); + } + } + } + } +} diff --git a/VSTestHost/TesterTestAdapter.cs b/VSTestHost/TesterTestAdapter.cs index 4516597..ae6863b 100644 --- a/VSTestHost/TesterTestAdapter.cs +++ b/VSTestHost/TesterTestAdapter.cs @@ -48,19 +48,38 @@ private async Task Connect( string executable, Version version, string hive, + IRunContext runContext, + ITestElement currentTest, CancellationToken cancel ) { + var hiveOption = string.IsNullOrEmpty(hive) ? "" : (" /rootSuffix " + hive); + if (_ide != null && _remote != null && application == _currentApplication && executable == _currentExecutable && version == _currentVersion && hive == _currentHive) { + if (runContext != null) { + SendMessage( + runContext, + string.Format(Resources.VSReuseMessage, application, executable, version, hiveOption), + currentTest + ); + } return; } Close(); + if (runContext != null) { + SendMessage( + runContext, + string.Format(Resources.VSLaunchMessage, application, executable, version, hiveOption), + currentTest + ); + } + Internal.VisualStudio ide = null; try { ide = await Internal.VisualStudio.LaunchAsync(application, executable, version, hive, cancel); @@ -141,7 +160,11 @@ private bool IsClientAlive() { /// /// The context for the current test run. /// - private async Task InitializeWorker(TestProperties vars) { + private async Task InitializeWorker( + TestProperties vars, + IRunContext runContext, + ITestElement currentTest = null + ) { string application, executable, versionString, hive; Version version; string launchTimeoutInSecondsString; @@ -165,7 +188,7 @@ private async Task InitializeWorker(TestProperties vars) { } // VSHive is the optional hive like 'Exp' - hive = vars[VSTestProperties.VSHive.Key] ?? VSTestProperties.VSHive.Exp; + hive = vars[VSTestProperties.VSHive.Key]; if (!vars.TryGetValue(VSTestProperties.VSLaunchTimeoutInSeconds.Key, out launchTimeoutInSecondsString) || !int.TryParse(launchTimeoutInSecondsString, out launchTimeoutInSeconds)) { @@ -178,7 +201,7 @@ private async Task InitializeWorker(TestProperties vars) { application ?? "(null)", executable ?? "(null)", version != null ? version.ToString() : "(null)", - hive ?? "(null)" + hive ?? "(default)" )); } @@ -205,7 +228,7 @@ private async Task InitializeWorker(TestProperties vars) { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(launchTimeoutInSeconds)); try { - await Connect(application, executable, version, hive, cts.Token); + await Connect(application, executable, version, hive, runContext, currentTest, cts.Token); } catch (OperationCanceledException ex) { throw new TimeoutException(string.Format(Resources.VSLaunchTimeout, launchTimeoutInSeconds), ex); } catch (Exception ex) { @@ -216,8 +239,8 @@ private async Task InitializeWorker(TestProperties vars) { } } - private static TestRunTextResultMessage GetFailure(Exception ex, Guid runId) { - var res = new TestRunTextResultMessage(runId, ex.Message); + private static TextTestResultMessage GetFailure(Exception ex, Guid runId, ITestElement currentTest) { + var res = new TextTestResultMessage(runId, currentTest, ex.Message); #if DEBUG if (ex.InnerException != null) { res.SystemException = ex.InnerException; @@ -228,25 +251,22 @@ private static TestRunTextResultMessage GetFailure(Exception ex, Guid runId) { private bool InitializeForTest(ITestElement testElement, IRunContext runContext) { var runId = runContext.RunConfig.TestRun.Id; - TestRunTextResultMessage failure = null; + TestResultMessage failure = null; - try { + try { var vars = new TestProperties(testElement, runContext.RunConfig.TestRun.RunConfiguration); - InitializeWorker(vars).GetAwaiter().GetResult(); + InitializeWorker(vars, runContext, testElement).GetAwaiter().GetResult(); _remote.Initialize(_runContext); AttachDebuggerIfNeeded(runContext, _ide, vars); } catch (ArgumentException ex) { - failure = GetFailure(ex, runId); + failure = GetFailure(ex, runId, testElement); } catch (TimeoutException ex) { - failure = GetFailure(ex, runId); + failure = GetFailure(ex, runId, testElement); } catch (InvalidOperationException ex) { - failure = GetFailure(ex, runId); + failure = GetFailure(ex, runId, testElement); } catch (Exception ex) { - failure = new TestRunTextResultMessage( - runId, - string.Format("{0}: {1}{2}{3}", ex.GetType().Name, ex.Message, Environment.NewLine, ex) - ); + failure = GetFailure(ex, runId, testElement); failure.SystemException = ex; } @@ -261,7 +281,7 @@ private bool InitializeForTest(ITestElement testElement, IRunContext runContext) private void AttachDebuggerIfNeeded(IRunContext runContext, Internal.VisualStudio ide, TestProperties vars) { var config = runContext.RunConfig.TestRun.RunConfiguration; if (!config.IsExecutedUnderDebugger || ide == null) { - return; + return; } // If we're debugging, tell our host VS to attach to the new VS diff --git a/VSTestHost/VSTestHostPackage.cs b/VSTestHost/VSTestHostPackage.cs index 54fa762..aa9e278 100644 --- a/VSTestHost/VSTestHostPackage.cs +++ b/VSTestHost/VSTestHostPackage.cs @@ -30,7 +30,7 @@ namespace Microsoft.VisualStudioTools.VSTestHost.Internal { [PackageRegistration(UseManagedResourcesOnly = true, RegisterUsing=RegistrationMethod.Assembly)] - [InstalledProductRegistration("#110", "#112", "1.0.2", IconResourceID = 400)] + [InstalledProductRegistration("#110", "#112", "1.0.3", IconResourceID = 400)] [ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string)] [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)] [RegisterHostAdapter("VSTestHost", typeof(TesterTestAdapter), typeof(TesterTestControl))] @@ -84,13 +84,13 @@ protected override void Initialize() { typeof(TesterDebugAttacher), "debug", WellKnownObjectMode.SingleCall - ); - - // Register for notifications when we start debugging. This is used - // so we can start listening for incoming calls to DebugAttacher - // only when necessary. - UIContext.FromUIContextGuid(new Guid(UIContextGuids.Debugging)).UIContextChanged += DebuggingChanged; - + ); + + // Register for notifications when we start debugging. This is used + // so we can start listening for incoming calls to DebugAttacher + // only when necessary. + UIContext.FromUIContextGuid(new Guid(UIContextGuids.Debugging)).UIContextChanged += DebuggingChanged; + base.Initialize(); } @@ -119,8 +119,8 @@ async void DebuggingChanged(object sender, UIContextChangedEventArgs e) { // Abort waiting in case we stopped within the timeout TesterDebugAttacherShared.CancelWait(); } - } - + } + public static string GetChannelName(Process process) { return string.Format("VSTestHost_{0}_{1:X8}_06420E12_C5A1_4EEF_B604_406E6A139737", process.MainModule.ModuleName.ToLowerInvariant(), diff --git a/VSTestHost/source.extension.vsixmanifest b/VSTestHost/source.extension.vsixmanifest index 72f0fd2..4f4044e 100644 --- a/VSTestHost/source.extension.vsixmanifest +++ b/VSTestHost/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + VSTestHost Allows UI testing of the Visual Studio IDE.