Skip to content

Instantly share code, notes, and snippets.

@mkropat
Last active January 8, 2017 18:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkropat/d8b744c994eaa59493648f8795d9dde8 to your computer and use it in GitHub Desktop.
Save mkropat/d8b744c994eaa59493648f8795d9dde8 to your computer and use it in GitHub Desktop.
Calculate the value for just about any constant in the Windows SDK
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $Name
)
$ErrorActionPreference = 'Continue'
function Main {
$buildDir = New-TemporaryDirectory
Push-Location $buildDir
try {
$sourcePath = Join-Path $buildDir 'getconstant.cpp'
Get-ConstantCppSource $Name | Out-File $sourcePath -Encoding ascii
Set-VisualStudioEnvironmentVariables
& (Get-ClPath) /EHsc $sourcePath 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Error "Unable to locate constant '$Name'"
exit 1
}
& $buildDir\getconstant.exe
}
finally {
Pop-Location
Remove-Item -Recurse $buildDir
}
}
function Get-VisualStudioToolsPath {
$toolsDir = 99..1 |
foreach { Get-EnvironmentVariable "VS${_}0COMNTOOLS" } |
where { $_ } |
select -First 1
if (-not $toolsDir) {
throw "Unable to locate Visual Studio install directory. Have you installed it?"
}
Write-Output $toolsDir
}
function Get-ClPath {
$toolsDir = Get-VisualStudioToolsPath
$binDir = Resolve-Path "$toolsDir\..\..\VC\bin"
Join-Path $binDir 'cl.exe'
}
function Get-IncludeDir {
if (-not (Test-Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots')) {
throw "Unable to locate Windows 10 SDK. Have you installed it?"
}
$sdkDir = Get-ItemPropertyValue "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" -Name KitsRoot10
$includeDir = Join-Path $sdkDir 'Include'
$newestVersion = Get-ChildItem $includeDir |
sort Name -Descending |
select -First 1 -ExpandProperty Name
Join-Path $includeDir $newestVersion
}
function Get-IncludeFiles {
param(
[string] $Name
)
Get-ChildItem (Get-IncludeDir) -Recurse -Include '*.h' |
where {
Select-String -Path $_ -SimpleMatch -CaseSensitive -Pattern "#define $Name" -List
}
}
function Get-ConstantCppSource() {
param(
[string] $Name
)
$includes = Get-IncludeFiles $Name | foreach { "#include <$($_.Name)>" }
@"
#include <iostream>
#include <Windows.h>
$($includes -join "`n")
using namespace std;
void repr(void *value) { cout << (long)value << endl; }
void repr(int value) { cout << value << endl; }
void repr(unsigned int value) { cout << value << endl; }
void repr(long value) { cout << value << endl; }
void repr(unsigned long value) { cout << value << endl; }
void repr(char* value) { cout << '\"' << value << '\"' << endl; }
int main()
{
repr($Name);
return 0;
}
"@
}
function Set-VisualStudioEnvironmentVariables {
if ($env:DevEnvDir) {
return
}
$toolsDir = Get-VisualStudioToolsPath
$batPath = [IO.Path]::GetTempFileName() -replace 'tmp$','bat'
@"
@echo off
call "$toolsDir\VsDevCmd.bat"
set
"@ | Out-File -Encoding ascii $batPath
& $env:ComSpec /c $batPath | foreach {
$parts = $_.Split('=', 2)
[Environment]::SetEnvironmentVariable($parts[0], $parts[1], [EnvironmentVariableTarget]::Process)
}
Remove-Item $batPath
}
function Get-EnvironmentVariable {
param(
[string] $Name
)
[Environment]::GetEnvironmentVariable($Name, [EnvironmentVariableTarget]::Process)
}
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
Main
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $Name
)
$ErrorActionPreference = 'Continue'
function Main {
$buildDir = New-TemporaryDirectory
Push-Location $buildDir
try {
$sourcePath = Join-Path $buildDir 'getconstant.cpp'
Get-ConstantCppSource $Name | Out-File $sourcePath -Encoding ascii
Set-VisualStudioEnvironmentVariables
& (Get-ClPath) /EHsc $sourcePath 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Error "Unable to locate constant '$Name'"
exit 1
}
& $buildDir\getconstant.exe
}
finally {
Pop-Location
Remove-Item -Recurse $buildDir
}
}
function Get-VisualStudioToolsPath {
$toolsDir = 99..1 |
foreach { Get-EnvironmentVariable "VS${_}0COMNTOOLS" } |
where { $_ } |
select -First 1
if (-not $toolsDir) {
throw "Unable to locate Visual Studio install directory. Have you installed it?"
}
Write-Output $toolsDir
}
function Get-ClPath {
$toolsDir = Get-VisualStudioToolsPath
$binDir = Resolve-Path "$toolsDir\..\..\VC\bin"
Join-Path $binDir 'cl.exe'
}
function Get-IncludeDir {
if (-not (Test-Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots')) {
throw "Unable to locate Windows 10 SDK. Have you installed it?"
}
$sdkDir = Get-ItemPropertyValue "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" -Name KitsRoot10
$includeDir = Join-Path $sdkDir 'Include'
$newestVersion = Get-ChildItem $includeDir |
sort Name -Descending |
select -First 1 -ExpandProperty Name
Join-Path $includeDir $newestVersion
}
function Get-IncludeFiles {
param(
[string] $Name
)
Get-ChildItem (Get-IncludeDir) -Recurse -Include '*.h' |
where {
Select-String -Path $_ -SimpleMatch -CaseSensitive -Pattern "#define $Name" -List
}
}
function Get-ConstantCppSource() {
param(
[string] $Name
)
$includes = Get-IncludeFiles $Name | foreach { "#include <$($_.Name)>" }
@"
#include <iostream>
#include <Windows.h>
$($includes -join "`n")
using namespace std;
void repr(void *value) { cout << (long)value << endl; }
void repr(int value) { cout << value << endl; }
void repr(unsigned int value) { cout << value << endl; }
void repr(long value) { cout << value << endl; }
void repr(unsigned long value) { cout << value << endl; }
void repr(char* value) { cout << '\"' << value << '\"' << endl; }
int main()
{
repr($Name);
return 0;
}
"@
}
function Set-VisualStudioEnvironmentVariables {
if ($env:DevEnvDir) {
return
}
$toolsDir = Get-VisualStudioToolsPath
$batPath = [IO.Path]::GetTempFileName() -replace 'tmp$','bat'
@"
@echo off
call "$toolsDir\VsDevCmd.bat"
set
"@ | Out-File -Encoding ascii $batPath
& $env:ComSpec /c $batPath | foreach {
$parts = $_.Split('=', 2)
[Environment]::SetEnvironmentVariable($parts[0], $parts[1], [EnvironmentVariableTarget]::Process)
}
Remove-Item $batPath
}
function Get-EnvironmentVariable {
param(
[string] $Name
)
[Environment]::GetEnvironmentVariable($Name, [EnvironmentVariableTarget]::Process)
}
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
Main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment