Wednesday, December 10, 2008

Vista x64

A new Dell Latitude E6500 with Vista x64 installed appeared in my office the other day. Its 4GB of RAM makes it a capable machine, but its black finish seems to attract dust and fingerprints. I'm always wiping it with my shirtsleeve to retain that shiny, brand-new look.

One of our applications exhibits unusual behavior when running on it. This application uses the 32-bit Oracle Data Provider. We've got several builds of this application available at any given time. Builds compiled with a 'Release' configuration have no problems. 'Debug' builds are a different matter. Certain 'modules', which are actually dynamically loaded assemblies, don't load at all. Examination of the Event Log reveals that BadImageFormatExceptions are being thrown from the Oracle.DataAccess assembly. This is mysterious because all of the modules use this assembly so I would think that none of them would load. This requires more investigation. There are some workarounds for this condition but I haven't had the time to yet implement them. I don't want to alter my OS setup so drastically that it dramatically differs from end-users' machines. Then again, none of the users are going to be running Vista x64.


<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>


I hope that Vista x64 will play nicer with Visual Studio 2008. Currently, VS2008 crashes when I return to the office in the morning if I leave it running overnight on my XP Pro machine.

Thursday, October 9, 2008

Editing multiple VS2008 project files with PowerShell

I recently needed to change reference paths for multiple project files in a solution. In the past I had done this manually, which was inefficient and frustrating. It occurred to me that PowerShell would alleviate the tediousness of this task.

Did I mention that the project files were under TFS version control? I created the following helper function to check out the files. I didn't create a corresponding function to check in the files because I wanted to eyeball them before check-in.


function CheckOutTfsFile([string] $FilePath)
{
Write-Host("Attempting to check out " + $FilePath)
$tfsvc = Get-TFSVersionControl
$ws = $tfsvc.GetWorkspace((Get-Item $FilePath).DirectoryName)
$ws.PendEdit($FilePath)
}


So here's the actual code. I needed to alter part of the path to the 'Common' project in 30+ Visual Studio 2008 project files. Specifically, I needed to change every instance of 'Common\Main' to 'Common\Production\2.4.0.0' to support a source code branch.


PS H:\> $projectLocation = "C:\Source\Project\Production\2.4.0.0"
PS H:\> $files = get-childitem $projectLocation -include *.*proj -recurse |
Select-String -pattern "Common\Main" -SimpleMatch |
Select-Object -Property Path
PS H:\> $files | Foreach-Object { CheckOutTfsFile( $_.Path) }
PS H:\> $match = "Common\\Main"
PS H:\> $replacement = "Common\Production\2.4.0.0"
PS H:\> $files | Foreach-Object
{ (Get-Content -Path $_.Path -encoding UTF8 )
-replace $match, $replacement
| Set-Content $_.Path -encoding UTF8 }


It worked out very well for me. All of the files were updated in a few seconds. I compared a few against their previous versions and it all looked good. Checked it into Team Foundation Version Control, started a manual CruiseControl build, and I was done.

There's definitely room for improvement in the name of reusability. I don't expect to have to do this too often, however, so I'm going to defer that for another day.

Friday, April 18, 2008

TFS Pain

We recently migrated the source code of one of our products (which I'll call ACME) from Visual Source Safe to Team Foundation Version Control. This change necessitated a change to the ACME's project configuration in CruiseControl.NET. While not as painful as surgery, the procedure was extraordinarily frustrating.

You might wonder why we're using CC.NET if the TFS Build Server is available. It's all a matter of timing. ACME is a 2+ year migration of an existing application written in Oracle Forms. We're near the end of the project and CC.NET has performed admirably the entire time. It was disruptive enough to educate everyone on TFS in order to use WorkItem Tracking and source control. I just want to finish the migration at this point so TFS Build can wait a couple more months.

I started the process on 4/18/2008 by configuring the development CC.NET server to use our development TFS source control. Installing the CC.NET TFS plugin was easy enough. I then created a local account on the TFS machine that had the same name and password as the owner of the CC.NET service. I then granted read permissions to this account so that it could access the ACME source code. I was able to successfully build in a really short period of time. It was now time for the real thing.

Repeating the process that I'd used in the development environment, I installed the CC.NET TFS plugin. And the install consisted of copying the TFS plugin files from the development server to the production server. Upon starting the CC.NET service I received the following exception in the Event Log:


Event Type: Error
Event Source: CCService
Event Category: None
Event ID: 0
Date: 4/18/2008
Time: 4:04:03 PM
User: N/A
Computer: CORP-TWDEV
Description:
Service cannot be started. System.BadImageFormatException: The format of the file 'ccnet.vsts.plugin.dll' is invalid.
File name: "ccnet.vsts.plugin.dll"
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm)
at Exortech.NetReflector.NetReflectorTypeTable.Add(String path, String searchPattern)
at ThoughtWorks.CruiseControl.Core.Config.NetReflectorConfigurationReader..ctor()
at ThoughtWorks.CruiseControl.Core.CruiseServerFactory.NewConfigurationService(String configFile)
at ThoughtWorks.CruiseControl.Core.CruiseServerFactory.Create(Boolean remote, String configFile)
at ThoughtWorks.CruiseControl.Service.CCService.CreateAndStartCruiseServer()
at ThoughtWorks.CruiseControl.Service.CCService.OnStart(String[] args)
at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)

=== Pre-bind state information ===
LOG: Where-ref bind. Location = C:\CI\CruiseControl.NET\server\ccnet.vsts.plugin.dll
LOG: Appbase = C:\CI\CruiseControl.NET\server\
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===

LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/CI/CruiseControl.NET/server/ccnet.vsts.plugin.dll.


Here was my first problem. My development environment was running a newer version of CC.NET based on the .NET 2.0 framework. Our production environment was running against the .NET 1.1 framework. The TFS plugin is a .NET 2.0 application. I would have to upgrade CC.NET on our production server before I could proceed. This was an unexpected development.

So I backed up all of my CC.NET configuration files and upgraded. The upgrade went smoothly and was fast. The service started this time. But my builds were failing with no explanation. I dove into the CC.NET log file.

Ah, here was the culprit!

2008-04-18 16:30:47,458 [5940:INFO] Force Build for project: ACME
2008-04-18 16:30:47,458 [5940:INFO] Project: 'ACME' is added to queue: 'ACME' in position 0.
2008-04-18 16:30:47,552 [ACME:INFO] Project: 'ACME' is first in queue: 'ACME' and shall start integration.
2008-04-18 16:30:47,645 [ACME:ERROR] INTERNAL ERROR: Could not load file or assembly 'Microsoft.TeamFoundation.VersionControl.Client, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
----------
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.TeamFoundation.VersionControl.Client, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.TeamFoundation.VersionControl.Client, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at ThoughtWorks.CruiseControl.Core.Sourcecontrol.Vsts.GetModifications(IIntegrationResult from, IIntegrationResult to)
at ThoughtWorks.CruiseControl.Core.Sourcecontrol.MultiSourceControl.GetModifications(IIntegrationResult from, IIntegrationResult to)
at ThoughtWorks.CruiseControl.Core.Sourcecontrol.QuietPeriod.GetModifications(ISourceControl sourceControl, IIntegrationResult lastBuild, IIntegrationResult thisBuild)
at ThoughtWorks.CruiseControl.Core.IntegrationRunner.Integrate(IntegrationRequest request)
at ThoughtWorks.CruiseControl.Core.Project.Integrate(IntegrationRequest request)
at ThoughtWorks.CruiseControl.Core.ProjectIntegrator.Integrate()
at ThoughtWorks.CruiseControl.Core.ProjectIntegrator.Run()

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

The TFS version 9 assemblies, which were installed on the development box, couldn't be found by the CC.NET TFS plugin on production. Why not? We were using Visual Studio 2005 at the time so I'd continued to use the version 8 assemblies on the production server. Anyway, I now had to go back to the TFS plugin site on CodePlex and get the version that worked against the 8.0 binaries installed on my production build server. Could I have just copied the version 9 assemblies from dev to prod? Sure, but I was getting concerned about the number of changes I was suddenly making to the build server. (I've since upgraded to Version 9.)

So back to CodePlex I go, or tried. Some corporate firewall change had been made, and every time I tried to go to CodePlex I got this error message: "Internet Explorer cannot download View.aspx from www.codeplex.com." At least IE7 gave me an error message- Firefox just displayed a page of control characters. I used Remote Desktop to connect to some different machines and was finally able to access CodePlex using IE 6. Got the 1.3 version of the TFS plugin and was ready to build!

But not so fast...

2008-04-18 16:49:28,306 [ACME:INFO] Project: 'ACME' is first in queue: 'ACME' and shall start integration.
2008-04-18 16:49:28,306 [ACME:DEBUG] Checking Team Foundation Server for Modifications
2008-04-18 16:49:28,306 [ACME:DEBUG] From: 4/18/2008 9:28:47 AM - To: 4/18/2008 4:49:28 PM
2008-04-18 16:49:28,384 [ACME:ERROR] INTERNAL ERROR: TF30063: You are not authorized to access http://tfs:8080.

Nice. OK, it seems that though I had two identically named accounts on both the build and TFS server, the passwords were different. So I synchronized the passwords, which then broke my Oracle continuous integration solution. The Oracle CI project still lives in VSS because the Visual Studio Team System 2008 Team Foundation Server MSSCCI Provider doesn't work correctly for us. This VSS instance is on yet another machine so I had to sync another password and then the Oracle project was back online.

And then this,

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets (3340,9): errorMSB3482: SignTool reported an error 'Key not valid for use in specified state. '.

We're still using a temporary key to sign the ClickOnce manifest. Something somewhere changed and I had to supply a password. This required logging into the build server using the credentials of the local account used to run the CruiseControl.NET service. And to be able to do that I had to login to the machine and add the local account to the Remote Desktop Users group.

Ah, so finally I'm finished, right? No.

ThoughtWorks.CruiseControl.Core.CruiseControlException: Unable to load
transform: e:\dev\CruiseControl.NET\webdashboard\xsl\msbuild.xsl --->
System.Xml.Xsl.XslLoadException: XSLT compile error. An error occurred
at e:\dev\CruiseControl.NET\webdashboard\xsl\msbuild.xsl(0,0). --->
System.Xml.XmlException: For security reasons DTD is prohibited in
this XML document. To enable DTD processing set the ProhibitDtd
property on XmlReaderSettings to false and pass the settings into
XmlReader.

The previous version of CC.NET had been based on the .NET 1.1 framework, which allowed DTD's. The version of CC.NET that I had just upgraded to doesn't allow DTD's. because it's based on the 2.0 .NET framework. Some of the XSL files that ship with CC.NET use DTD's. Google to the rescue again.

Thursday, January 10, 2008

GAC Spelunking

I've been working on a tool based on the .NET 3.5 framework to unify our old software change management tools with TFS. I published the ClickOnce application but of course had forgotten to set the TFS 'Copy Local' references to True. I quickly discovered that there were a number of supporting TFS assemblies that needed to be included in my ClickOnce application manifest so I started a trial and error process of adding them all from C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies. A couple of failed installs later I hit a wall trying to find 9.0 version of Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll. This assembly was in the GAC but not accessible on my file system. I remembered a trick using the SUBST command to map the GAC to a drive.


subst M: c:\Windows\assembly\gac_32

M:\>dir *TeamFoundation.WorkItemTracking*
Volume in drive M has no label.
Volume Serial Number is 9C00-A7F3

Directory of M:\

12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Client
12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Client.Cache
12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore
12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Client.Provision
12/03/2007 12:42 PM Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage
12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Client.RuleEngine
12/03/2007 01:45 PM Microsoft.TeamFoundation.WorkItemTracking.Proxy

0 File(s) 0 bytes
7 Dir(s) 30,894,231,552 bytes free

M:\>cd *Proxy*

M:\Microsoft.TeamFoundation.WorkItemTracking.Proxy>cd 9.0*

M:\Microsoft.TeamFoundation.WorkItemTracking.Proxy\9.0.0.0__b03f5f7f11d50a3a>dir

Volume in drive M has no label.
Volume Serial Number is 9C00-A7F3

Directory of M:\Microsoft.TeamFoundation.WorkItemTracking.Proxy\9.0.0.0__b03f5f
7f11d50a3a

12/03/2007 01:43 PM .
12/03/2007 01:43 PM ..
12/03/2007 01:43 PM 122,880 Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll
1 File(s) 122,880 bytes
2 Dir(s) 30,893,748,224 bytes free

M:\Microsoft.TeamFoundation.WorkItemTracking.Proxy\9.0.0.0__b03f5f7f11d50a3a>


The assembly is now exposed and can be copied to a location that can be referenced by VS2008. Crisis averted.

Monday, January 7, 2008

Media Center

Components
  • Antec New Solution Series NSK2400 Mini Tower Case (Silver) Retail (380W power supply)
  • Intel Core 2 Duo E6300 Conroe Processor 1.86GHz, 1066FSB, LGA775, 2MB Cache Retail
  • Corsair TWIN2X2048-5400C4 2GB DDR2-675 XMS2-5400 Xtreme Performance Memory w/Black Heat Spreader Retail
  • MSI 945GCM5-F Intel Core 2 Duo (Desktop) Socket 775 1066 MHz PC2-5400 (DDR2-667) mATX Motherboard Retail
  • EVGA e-GeForce 7600 GS (256-P2-N549-TX)
  • Hauppauge WinTV-PVR-500 MCE
  • Western Digital Caviar SE16 (750GB OEM)
  • SAMSUNG SH-S203N 20X SATA DVD Burner Black Drive Bulk
  • Vista Ultimate
Notes
  • Assembled with no problem. Well, I was frightened during the attachment of the Intel heatsink / fan. I thought that I was going to snap the mobo into two pieces. Started up with zero problems at all, which I assume is a credit to modern mobo architecture.
  • Divx and Xvid codecs seem to get installed somewhere between BeyondTV 4.4 and 4.7

Problems
  • I initially installed Vista Home Premium. This was a big mistake because it doesn't have Remote Desktop.
  • Live TV is not at the quality that I would prefer. Channels 2-5 come in great, but the other channels seem to experience signal interference. I'm sure that I'll be able to resolve this problem in the future.
  • Haven't experienced any heat-related problems yet, but it is a concern for the summer months. The media center sits in my entertainment center behind a glass door. The only ventilation is through a 1.5" by 6" slit in the back through which wires are run.
Conclusion
I'm really happy that I built this and wish that I had done months ago.