Wednesday, September 30, 2009

PowerShell – Compiling with csc.exe – more of a headache that it should have been. It is possible…

I was attempting to use PowerShell to compile a group of *.cs source files – needing the flexibility of programmatically swapping out dependent assembly references at compile time depending on certain build conditions… Don’t want to get too much in to why I needed it, just that it is doable – (more painful than initially expected), but still possible.

First let’s get a csc command we want to compile.

Second let me state that this was more of an exercise in wanting to learn PowerShell and there probably other ways of accomplishing what I needed, just seemed like a good time to start down the painful learning curve. Also note, I’m not a CSC compiler pro – I haven’t analyzed each of the “options” and weather it’s right/wrong/best practice – it just works… (thanks to Visual Studio & MSBuild for hiding how we actually should use the compiler)

Ok take a simple csc compile command – (In Visual Studio – File –> New Project -> ClassLibrary1 as a good starting point). Compile the project & check the build output window. You’ll get an output similar to the below.

C:\Windows\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll" /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.DataSetExtensions.dll" /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\PowershellCscCompileSample.dll /target:library Class1.cs Properties\AssemblyInfo.cs

Next figure how the heck to execute this in PowerShell.

& $csc $params --- NOPE
exec $csc $params – NOPE

I must have tried tens if not hundreds of methods to get the simple thing above to compile… needless to say I pinged a co-worker for some help. http://obsidience.blogspot.com/

His pointer – when trying to get big string command to execute in powershell do the following.

  1. Open up “Windows PowerShell ISE”  (on Windows 7)
  2. Paste the command prompt window (with an “&” at the beginning)
  3. look for any coloration changes like…
     image
  4. Next place PowerShell escape character [`] in front of any character where the coloration changes (They’re very subtle so look long and hard)
     image

We should now have a PowerShell string that compiles our project.

After I got that far – I cleaned up the compiler syntax for a little re-use. (You can download the project blow to check it out)

If you don’t want to see the entire csc compile in the project download above, below is the general usage…



################## Build Configuration ##################
$project_name = 'PowershellCscCompileSample'
$build_configuration = 'Debug'
#########################################################

$core_assemblies_path = 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5'
$framework_assemblies_path = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727'

function global:Build-Csc-Command {
param([array]$options, [array]$sourceFiles, [array]$references, [array]$resources)

$csc = 'C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe'

# can't say I'm doing delimeters correctly, but seems to work ???
$delim = [string]""""

$opts = $options

if($references.Count -gt 0)
{
$opts += '/reference:' + $delim + [string]::Join($delim + ' /reference:' + $delim, $references) + $delim
}

if($resources.Count -gt 0)
{
$opts += '/resource:' + $delim + [string]::Join($delim + ' /resource:' + $delim, $resources) + $delim
}

if($sourceFiles.Count -gt 0)
{
$opts += [string]::Join(' ', $sourceFiles)
}

$cmd = [string]::Join(" ", $options)
$cmd = $csc + " " + $opts
$cmd;
}

function global:Execute-Command-String {
param([string]$cmd)

# this drove me crazy... all I wanted to do was execute
# something like this (excluding the [])
#
# [& $csc $opts] OR [& $cmd]
#
# however couldn't figure out the correct powershell syntax...
# But I was able to execute it if I wrote the string out to a
# file and executed it from there... would be nice to not
# have to do that.

$tempFileGuid = ([System.Guid]::NewGuid())
$scriptFile = ".\temp_build_csc_command-$tempFileGuid.ps1"
Remove-If-Exist $scriptFile

Write-Host ''
Write-Host '*********** Executing Command ***********'
Write-Host $cmd
Write-Host '*****************************************'
Write-Host ''
Write-Host ''

$cmd >> $scriptFile
& $scriptFile
Remove-If-Exist $scriptFile
}

function global:Remove-If-Exist {
param($file)
if(Test-Path $file)
{
Remove-Item $file -Force -ErrorAction SilentlyContinue
}
}

$resources = @(
#""
)

$references = @(
"$core_assemblies_path\System.Core.dll",
"$framework_assemblies_path\System.dll"
)

$sourceFiles = @(
#""
)

$sourceFiles += Get-ChildItem '.' -recurse `
| where{$_.Extension -like "*.cs"} `
| foreach {$_.FullName} `

$debug = if($build_configuration.Equals("Release")){ '/debug-'} else{ "/debug+" }

$options = @(
'/noconfig',
'/nowarn:1701`,1702', # Note: the escape [`] character before the comma
'/nostdlib-',
'/errorreport:prompt',
'/warn:4',
$debug,
"/define:$build_configuration``;TRACE", # Note: the escape [`] character before the comma
'/optimize+',
"/out:$project_name\bin\$build_configuration\ClassLibrary.dll",
'/target:library'
)

$cmd = Build-Csc-Command -options $options -sourceFiles $sourceFiles -references $references -resources $resources

Execute-Command-String $cmd
 
  

Tuesday, September 15, 2009

How do I get UISpy.exe on my Windows 7 Developer Machine?

I know there’s a tool somewhere in some SDK called UISpy.exe. It looks like this.

ms727247.UI_Spy_Main_Window(en-us,VS.90)[1]

You can read all about it here - http://msdn.microsoft.com/en-us/library/ms727247.aspx

But can you find it?

The docs in that link above state…

ms727247.alert_note(en-us,VS.90).gifNote: UI Spy is installed with the Microsoft Windows SDK. It is located in the \bin folder of the SDK installation path (uispy.exe) or can be accessed from the Start menu (Start\All Programs\Microsoft Windows SDK\Tools\UISpy).

If I go take a look at the (Start\All Programs\Microsoft Windows SDK\Tools\UISpy) as shown in the image below. UISpy is nowhere to be found.

image

In some forum post somewhere – I saw that I had to install the .Net Framework 3.0 SDK. Which is strange since I have the 3.5 framework already installed and the tool isn’t there. Oh well, I found it (I thought), downloaded it and tried to run the setup. Where in Windows 7 I was prompted with the following dialog.

You must use "Turn Windows features on or off" in the Control Panel to install or configure Microsoft .NET Framework 3.0.

Ok, fine I’ll do that…

image

Searching the list of features to turn on and off, the only one that looks anything like what I’m looking for (outlined in red) has already been installed.

image

Off to do more research…

Then I run into this blog http://blogs.msdn.com/windowssdk/archive/2008/02/18/where-is-uispy-exe.aspx

Eventually I download the Windows SDK for Vista Update. Run the install wizard with all the defaults except this screen…

As the blog post states – make sure you take a pre-install snapshot of the following registry key

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs
Before Install:image 

image 

After Install:
image

I reverted the changes back to v6.0A in the registry above…

And TAH-DAH UISpy.exe has been found.

C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\UISpy.exe

Pain in the A$$… But it seems to work.

 

Copyright 2008 All Rights Reserved - Revolution Theme - by Brian Gardner. Converted into Blogger Template by Bloganol dot com