Showing posts with label Visual Studio. Show all posts
Showing posts with label Visual Studio. Show all posts

Wednesday, May 26, 2010

Using robocopy with Visual Studio 2008 Post-build events

I have a solution that has about 15 odd projects in it.  It’s for an application that has multiple optional services with shared assemblies.  Hence the 15 projects.  I have an installer that lets the user pick from which of the optional bits to install.  For ease of maintenance, I version the installer with multiple folders.  Each version gets a folder for the installer source and a folder for the installable bits.

With Visual Studio, the default way of building a solution is to put the compiled assemblies and dependant files inside a bin folder for each project.  Each bin folder can multiple folders for different build options (debug, release, platform, etc).  I wanted a simple way of consolidating the files from each bin folder to a common folder for the installer.

I didn’t want to set the output path, from the Build tab on the project options page.  While I could direct all of the compiled output to a single folder, that would send symbol and vshost files over as well.  I didn’t want those files.  I only wanted just what I actually needed for deployment.

I decided on using the Post-build event for each project and copy only the files that I wanted.  I had already created a “deploy” folder from the solution root folder.  So I defined a build event with the following command line:

robocopy $(TargetDir) $(SolutionDir)Deploy *.exe *.dll


If you don’t know robocopy, it’s a powerful file and folder copy command line.  It’s been around for years in one Microsoft SDK or another and has been included as part of the OS since at least Vista.  In it’s simplest form, you specify the source folder, the destination folder.  It has a slew of options.


$(TargetDir) is a macro that represents the complete path for folder that the compiled units are created in, like bin\debug\ or bin\release\.  The $(SolutionDir) macro is the path to the solution folder.


I went to build one of the projects in the solution and it failed on the Post-build event.  Error 1, it said.  I copied the robocopy command line from the error message and ran it from a cmd prompt.  It executed without any errors and did exactly wat it was suppsoed to do.  After a little digging, I found out that robocopy returns 1 as an exit code to indicate success.  Since the dawn of time (January 1, 1970), command line programs have returned 0 for the exit code to indicate success and any other value to indicate an error.  It’s a bizarre flaw with an otherwise very useful tool.


Visual Studio 2008 does not appear to have any way of ignoring the exit code.  Well that’s just ducky.  So what I did was to bury the exit code in an unmarked grave so that Visual Studio 2008 wouldn’t be able to see or complain about it.  I created a batch file in the solution root folder and named it robopip.cmd.  Robopip has the following contents:


robocopy %1 %2 %3 %4 %5 %6 %7 %8 /R:1 /XF *vshost*
dir %TEMP% >nul


The first line executes the robocopy command with up to 8 parameters passed in by the build process.  The “/R:1” parameter basically says try once and then die.  The “/XF *vshost*” tells robocopy to ignore any file with “vshost” in the same.  The second line is crucial, it’s basically a low impact command to clear the last exit code.  We ask for the directory listing of the user’s temp folder and then toss away the results.  There is probably a more elegant way of clearing the error code, that was the first one that worked for me.


So now, I can use the following Post-event build command with each project.


$(SolutionDir)robopip $(TargetDir) $(SolutionDir)Deploy *.exe *.dll


I get the power of RoboCopy without Visual Studio squawking about the exit code.

Thursday, August 21, 2008

Using the test form from remote connections for .NET web services

I’m working on a web service using C# and targeting the .NET 2.0 Framework.  Nothing terribly fancy, but it has some code to log the caller’s IP address (via HttpContext.Current.Request.UserHostAddress).  While testing the code, I like using the test form functionality that .NET provides with web services.  By design, it only works locally.  If you try to use the test form from a remote machine, you’ll get the error:

The test form is only available for requests from the local machine

That’s fine, when you expose a web service you don’t want to make it too easy for people to start poking at your web service methods with a pointy stick.  Still, I wanted to test it from another machine and it saves time being able to enter in different values without having to code up a test framework.  Plus, I wanted to make sure that my code was reliably picking up the caller’s IP address.

After just a tiny bit of searching in the series of tubes, I found how to easily enable the web service test form for remote connections.  Juan Ignacio Gelos posted what you need to add to the web service web.config file to enable the test form.

<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
</system.web>
</configuration>



You are still limited to run methods that have simple data types as input, but it’s very handy for testing.  Since this setting lives in web.config, it’s easy to remove it when I run a build.  I’m using FinalBuilder on a dedicated build box and it’s easy to clean up .config files so that developer settings get scrubbed before the files get packages into an installer.

Wednesday, August 13, 2008

Using Delphi in a team

I was just reading

Tuesday, July 08, 2008

Still time to enter the Darwin Race of Languages

Do you think that hand tweaked C code runs circles around managed code (C#, Java, VB.NET)?  Or do you think that your Just In Time compiled managed code gets the job done more securely than those bit sniffing dinosaurs?  Anxious to prove that Delphi is still relevant?  Want to win some cutting edge component libraries from DevExpress?

If you answered “yes” to any of those questions, there is still time to enter the Darwin Race of Languages.  The brainchild of Sevensteps CTO Bart Roozendaal, the Darwin Race is pitting a slate of challengers using the compiler and IDE of their choice to write a utility that will solve one of three problems.  The projects are the following:

  • Temperatures and CPU load
    A utility that will measure CPU temperatures and CPU load on remote computers
  • Multi clipboard utility
    The utility should hold several entries that were place on the clipboard earlier. In effect it should replace the clipboard.
  • GUI to a command line program
    A GUI front end for the gbak database command line driven program for the Firebird database.

Each entry will be judged on the software itself and how you documented the design and development of the application.  The goal is not to see which development is best tool, but to see what tools are the best for different types of jobs.  To see where the strengths are and where are the weaknesses of each tool, using real world types of the problems.  The documentation part will share the development process and show how different people come up with solutions for similar problems.

There are already a bunch of sponsors lined up.  DevExpress will be giving away a a license for DXperience Enterprise or the VCL Subscription.  If you wint, you get to pick one of them.  I have DXperience and most of the VCL components, you can’t go wrong with either one of them.

The race is on already, but there is still time to join.  There are a bunch of participants already signed up, covering C#, Delphi, VB, and something on the Mac platform.  Java is not yet represented, does someone out there want to pick up the Java gauntlet?

Saturday, May 24, 2008

IPv6 and Vista

The other day, I read a post that Carl Franklin had made on his blog about a new Vista laptop that he had to buy on short notice.  The gist of his post that Vista ran pretty well, but he did tweak some of the settings.

One of the settings that Carl had tweaked was to disable IPv6 on all of the network adapters.  For some reason that jumped out at me.  I posted a comment on his blog asking why he did it.  I'm all for disabling services that are not being used, but I like to know what the reason is behind it. 

I did a quick scan through Google, and initially found many hits for how to disable IPv6 with very little explanation on why you should do it.  Carl responded to my comment that he had heard anecdotal evidence that IPv6 can cause conflicts under Vista.

For me, the decision to disable IPv6 on my Vista boxes boils down to two questions:  Do I need IPv6 functionality?  If I don't need IPv6, does having IPv6 enabled cause any problems under Vista?  Time to go back to Google and due some more searching.

One bit of trivia:  While I was searching for why you would want to disable IPv6 on Vista, I came across a few articles about how Google owns a large block of IPv6 space that works out to be 7.9 x 1028 IP addresses. That's a large number, no matter how you slice it.   Why does our Google Overlord need that many addresses?

I've seen the badge below displayed on a few sites. 

Pretty scary looking, huh?  There is a real concern with the number of IPv4 addresses being used up.  At the current rate of assignment, we just have a few years left before the all of the addresses have been assigned.  That's why they came up with IPv6, to provide for a virtually unlimited number of IP addresses.  Even with Google hogging billion and billions of IPv6 addresses, we'll still more than enough to serve this planets needs for the for seeable future.  Right now, the continued use of NAT allows more users to share the same IP address. 

We are seeing all of the IPv4 addresses being assigned, but that doesn't mean that they are all being used.  If you look at the global IPv4 allocation list, you'll see that large chunks of the IPv4 space is in the hands of a small number of companies.  For example, Apple owns all the 017.xxx.xxx.xxx addresses.  That's over 16 million distinct, global IP addresses.  What are they doing with all those addresses?  And some people still question the need for IPv6 in the first place. 

But I digress, I think we'll be safe with just IPv4 addresses for the next few years.  At this point, there are no IPv6 only addresses that I want to visit.  They exist, I just don't need to visit them.  So the answer to my first question is: No, I don't need IPv6.

So what about leaving IPv6 enabled in Vista?  What does that cost me?  I read about some reports early in the Vista release with IPv6 issues.  Some of that could be attributed to "version 1.0" network drivers.  I did read some reports of http://localhost not working with IPv6 enabled. 

On an IPv6 enabled box, localhost will evaluate to ::1, not the 127.0.0.1 that we call home.  That is what defined for localhost in %SystemRoot%\system32\drivers\etc\hosts as the IPv6 adddress for localhost.  This apparently causes a problem when testing locally hosted websites.  If you remove (or better yet, just comment out the ::1 entry from the hosts file, that was reported to allow web development to continue using localhost and IPv6 installed.

Klaus Graefensteiner has a pretty good explanation of why this is happening.  As noted elsewhere, he recommends editing the hosts file as the work around. I haven't done any web development on my Vista box, I can't verify that this is still an issue.  I'm actually planning on doing some web development work from my home machine in the near future, issues with localhost will pop up pretty much immediately. 

As far as I can tell, the answer to my second question is "maybe".  If the only issue is the localhost issue, then I'll address it through editing the hosts file as opposed to disabling IPv6 altogether.

I did see the value of one point that Carl made.  If the service is not being used, then disable it.  It's not enough of an issue for me, but resources are limited, then you want to pick off the low hanging fruits from the list of running services.  If you do actually want to disable IPv6 in Vista, it's pretty easy to disable or enable IPv6 support (from numerous sources, this one from TechSupportForum.Com)

  1. Go to Start and type in "ncpa.cpl" (without the quotes) and press Enter
  2. Right click on each network connection and select "Properties"
  3. Remove the checkmark from the box next to "Internet Protocol Version 6 (TCP/IPv6)
  4. Click OK to exit the dialog

Lather, rinse, and repeat for each network connection. IPv6 will still remains active for routing and tunneling.

To complete disable IPv^ in the system, you'll need to add a registry.  Go to registry and create DWORD parameter "DisabledComponents" in HKLM\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters and set it to a value of 0xff and restart the system.

Just remember one thing, if you disable IPv6, you will not be able to use Windows Meeting Space or any application that relies on the Windows Peer-to-Peer Networking platform or the Teredo transition technology.

Bonus Firefox tip:  You can disable Firefox's usage of IPv6 with out disabling IPv6 for the rest of the system.

In Firefox, type about:config and then in the filter box type dns. You'll see an entry named "network.dns.disableIPv6".  Double-click that line so that it reads True, which will effectively disabled IPv6 for Firefox.  You'll need to restart Firefox for this change to take effect.

Tuesday, April 29, 2008

I just installed the PowerCommands for Visual Studio 2008

I just installed the PowerCommands 1.1 for Visual Studio 2008.  This is a set of extensions to the VS 2008 IDE that provide some additional functionality.  The available commands are listed here.  The Collapse Projects command sounds pretty basic, but it's something I've always wanted and it's great for large solutions. 

The best part of PowerCommands?  You get the source code, which would be handy if you ever want to write your own VS extension.

Wednesday, April 16, 2008

Handy tip for debugging a Windows Service

Debugging a Windows Service is always a pain. You can't run a service like a regular application, you have to run it from Windows Service Control Manager (SCM) and then have your debugger attach to the process while it's running. The problem is that it's difficult to debug problems with the service startup as the debugger can't attach to the service in time.

I came across a tip on the .NET Tip of The Day site, "How to debug Windows Service startup". Basically, you just add a line that calls Debugger.Launch() or Debugger.Break() in your startup code. When your code hits one of those lines, the Visual Studio Just-In-Time Debugger dialog will be invoked and you can select your debugger to handle the error. That will allow you to continue along in the code and debug until the cows come home.

That works better than a service debugging tip I posted a couple of years back, calling the Sleep API in your startup code to allow enough time to attach a debugger to the service. That was a hack, this is much cleaner.

All in all, I still prefer to separate the functional code from the service specific code. I can then run that code from a desktop app, making it much easier to debug. That works about 99.9% of time. Every now and then, I do need to run the actual service code and the Debugger.XXXX() calls will make that task much easier.

Friday, March 28, 2008

When will the Visual Studio IDE catchup to the Delphi IDE?

Sometimes it just the little things that annoy you.  If I add a button to a Delphi form, by default it is named Button1.  If I double click on Button1, a Click event handler is added and is named Button1Click and wires it up to the button's OnClick event.  Visual Studio does pretty much the same thing.  Where they is differ is when you edit the button's name.

If I renamed Button1 to something more meaningful like DestroyAllMonsters, the Delphi IDE will rename the event handler to DestroyAllMonstersClick.  When you rename the button in the Visual Studio IDE, it doesn't touch the event handler.  That's annoying.

Another difference is how Delphi handles event handlers when your delete the code or never add the code.  When you double click on the button and get the new event handler automagically created and wired up to the control, that event handler has no code.  If you save that file, Delphi removes the event handler.  it does under the assumption that you didn't mean to have that event handler and it will clean up the code for you.  Like wise, if you delete the code out of the handler and save the file, Delphi will remove the handler. 

This makes it easy to cleanup code when you remove a control that you didn't really want or need any more.  Visual Studio doesn't do that for you, or least not in C#.  When you spend your day working in both IDE's at the same time, those types of annoyances really can be annoying.

Thursday, January 24, 2008

Copying files with VS 2008's port-build event under Vista

I'm still working on my SmugMug plugin for Windows Live Writer. I've ported it from VS 2005 to VS 2008, that was trivial. I'm at the point where I want to debug the plugin while it's being loaded from Live Writer. Normally, this is pretty straight forward. You use the post-build event to copy the plugin's files to the Live Writer plugin folder. For my plugin, I used the following build event:

xcopy /D /R /Y "$(TargetDir)s*.dll" "C:\Program Files\Windows Live\Writer\Plugins"

The next step is to go into the Debug settings for the project and set the Start Action to Start external program, setting it to the path to the Live writer executable. On my machine, that would be:

C:\Program Files\Windows Live\Writer\WindowsLiveWriter.exe

With that set, all I need to do is to press F5 and my plugin gets built, copied to the Live Writer plugin folder, then Live Writer gets launched. Sounds good, but when I did a test build to verify the files would get copied, I got the following error message:

"XCOPY /D /Y /R "C:\dev\DotNet\LiveWriter\SmugMug4WindowsLiveWiter\SmugMug4WLW\bin\Debug\s*.dll" "C:\Program Files\Windows Live\Writer\Plugins\"
" exited with code 4. SmugMug4WLWPlugin

Code 4? I had to get Mr Peabody to look that one up for me. DOS 3.2 ring a bell? At any rate, exit code 4 for xcopy is "Initialization error (not enough memory, invalid syntax, path not found)". That actually was a clue to what the problem was, I was just missing the obvious. I tried pasting that xcopy command into a Take Command shell window and it ran without errors. So the syntax was correct, something was blocking it.

D'oh! I'm doing this under Vista. Joe User can't just copy files into "program files" space, that's no longer allowed. Only administrators have write access to "program files" and I'm running VS2008 without elevation. I run my Take Command shell as admin, so of course it can write to the plugins folder.

To get around this, I decided to punch a hole through Vista's default rights for that folder and give everyone and their dog full access to it. I tried doing it through icacl, but I wasn't getting the syntax right. So I just opened up explorer, selected the plugins folder, right-clicked and selected "Properties". I then selected the "Security" tab and then selected Users under "Group or user name". Next, I clicked the edit button, to bring up the edit dialog for the access rights. I selected "Full Control" and then clicked "Ok" all the way home.

That fixed it. VS2008 was able xcopy my plugin without any errors.