Tuesday, May 07, 2013

VS2010 build error MSB8011: Failed to register output. Please try enabling Per-user Redirection or register the component from a command prompt with elevated permissions

This is a known issue. The cause and the solution are stated on a MSDN forum.
Here is an excerpt from that online forum:
Starting from Windows Vista, including Vista, Win2008 Server, Windows7, build process cannot write to HKEY_CLASSES_ROOT (HKCR) hives unless the process is started as administrator. To be able to register in non-administrator mode, VS2008 and VS2010 offer the feature of "registrer per user". The registration information is written to HKEY_CURRENT_USER (HKCU). You can set Linker -> General -> Per User ReDirections to "true" if Linker -> General -> Register Output is set to "true". If you have your own custom registration step, you can use the per user registration command: regsvr32 /s /n /i:user "xxxx.dll". If VS2010 is installed on Windows XP, you don't need to have the elevated privilege or per user registration to register your application since the security requirement is OS specific.

Monday, May 06, 2013

Sub functions in windows command line script

During my day-to-day work, I find myself frequently changing some environment variables on my Windows machine to compile my various projects. For example, some of them are targeted for visual studio 2008 and some are targeted for visual studio 2010 (don't ask me why this is the case).

Because I am lazy, I don't want to always click "Start"->Right click "Computer"->"Properties"->"Advanced system settings"->"Environment Variables..." to changes the environment variables that I care about (and there are so many variables to change). Instead, I prefer to open a command line windows and just execute one script that properly set all the variables for me, including the PATH environment variable.

Initially, I created a simple script (called dev.cmd) like below:
REM: file content for dev.cmd
set PATH=%PATH%:c:\mypath1
set PATH=%PATH%:c:\mypath2
...
set MYVAR1=myvar1
set MYVAR2=myvar2
...

However, when I have multiple command line windows open in front of me at the same time, I easily forgot whether or not I have executed dev.cmd in a particular windows when I switch to it. So I just blindly run the script again when I feel it is needed.

This approach gives me a little problem: when I need to look at my %PATH% later on to debug the cryptic build error message, resulted from running a binary from an unexpected location/path, the result is something like:
%SYSTEM_PREDEFINED_PATHS%:c:\mypath1:c:\mypath2:c:\mypath1:c:\mypath2:c:\mypath1:c:\mypath2:c:\mypath1:c:\mypath2:c:\mypath1:c:\mypath2:c:\mypath1:c:\mypath2

That is simply because I have executed my dev.cmd so many times.

So I find myself in the need of functionality that I can use to determine if mypath1 is already part of my %PATH%.

OK, that means sub functions in command line scripts. Fortunately I found it is supported. Unfortunately, I found it really hard to understand/remember.

So, I decide to paste a slighted modified version of my dev.cmd here, just for my reference (and for yours, if you find it useful). The interesting part is not the "set" statements, it is instead the three sub functions at the end, i.e., "add_path", "substring", and "dequote".

REM file content for dev.cmd

@echo off
set WS=c:\xxx\workspaces
set TCROOT=%WS%\build\toolchain
set BUILDAPPS=%WS%\build\apps\bin

set LOTUS_COMPCACHE=%WS%\lotus\main\gobuild\compcache
set GOBUILD_PTHREADS_W32_291_ROOT=%LOTUS_COMPCACHE%\pthreads-w32-291\ob-1005657\publish
set GOBUILD_DCERPC_WIN32_11_ROOT=%LOTUS_COMPCACHE%\dcerpc-win32-11\ob-1053621\publish
set GOBUILD_PTHREADS_W32_291_ROOT=%LOTUS_COMPCACHE%\pthreads-w32-291\ob-1005657\publish
set GOBUILD_BOOST1470_WIN64_VC90SP1_ROOT=%LOTUS_COMPCACHE%\boost1470_win64_vc90sp1\ob-811341\windows
set GOBUILD_AUTHENTICATION_FRAMEWORK_ROOT=%LOTUS_COMPCACHE%\authentication-framework\ob-1096390\windows-2008
set GOBUILD_PLATFORM_SDK_WINDOWS_ROOT=%LOTUS_COMPCACHE%\platform-sdk-windows\ob-1086025\publish

set JAVA_HOME=%TCROOT%\win64\jdk-1.7.0_09
set ANT_HOME=%TCROOT%\noarch\ant-1.7.1

set HTMLHELP_PATH=%TCROOT%\win32\htmlhelp-1.32
set GAWK_PATH=%TCROOT%\win32\gawk-3.1.6
set SED_PATH=%TCROOT%\win32\sed-4.1.4
set PERL_PATH=%TCROOT%\win32\perl-5.8.8
set WINSDK_PATH=%TCROOT%\win32\winsdk-7.0.7600
set WIX_PATH=%TCROOT%\win32\wix-3.5.2519.0
set VC_PATH=%WINSDK_PATH%\VC
set FRAMEWORK_PATH=%windir%\Microsoft.NET\Framework\v3.5
set CPU=AMD64

set INCLUDE=%VC_PATH%\atlmfc\Include;%VC_PATH%\Include;%WINSDK_PATH%\Include;
set LIB=%VC_PATH%\atlmfc\Lib\amd64;%VC_PATH%\lib\amd64;%WINSDK_PATH%\Lib\x64;
set LIBPATH=%FRAMEWORK_PATH%;%VC_PATH%\atlmfc\Lib\amd64;%VC_PATH%\lib\amd64;%WINSDK_PATH%\Lib\x64;

rem call :add_path %TCROOT%\win32\bin
call :add_path %WINSDK_PATH%\bin
call :add_path %VC_PATH%\bin
call :add_path %VC_PATH%\bin\amd64
call :add_path %VC_PATH%\bin\x86_amd64
call :add_path %VC_PATH%\vcpackages
call :add_path c:\python27
call :add_path "c:\Program Files (x86)\Windows Resource Kits\Tools"
call :add_path %BUILDAPPS%
call :add_path %ANT_HOME%\bin
call :add_path %JAVA_HOME%\bin
call :add_path %TCROOT%\win32\make-3.81
call :add_path %TCROOT%\win32\perl-5.8.8\bin
call :add_path %TCROOT%\win32\cygwin-1.5.19-4\bin
call :add_path %WIX_PATH%
call :add_path %HTMLHELP_PATH%
call :add_path %GAWK_PATH%\bin
call :add_path %SED_PATH%\bin
call :add_path %PERL_PATH%\bin
call :add_path %SystemRoot%\system32
call :add_path %SystemRoot%
call :add_path %SystemRoot%\SysWOW64\wbem
call :add_path %SystemRoot%\system32\wbem
call :add_path %WINSDK_PATH%\dll\amd64\Microsoft.VC90.DebugCRT
call :add_path "c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE"

cd /d %WS%
goto :eof

  :add_path
  setlocal
  set p1=%1
  call :dequote p1
  call :substring "%p1%" "%PATH%"
  if errorlevel 1 endlocal & call set PATH=%PATH%;%p1%& setlocal
  rem echo.new PATH is "%PATH%"
  endlocal
  goto :eof

  :substring
  setlocal
  set s1=%1
  set s2=%2
  call :dequote s2
  call :dequote s1
  echo."%s2%" | findstr /iC:"%s1%" 1>nul
  if errorlevel 1 (
    rem echo.%2 does NOT contain %1
  ) ELSE (
    rem echo.%2 contains %1
  )
  endlocal
  goto :eof

  :dequote
  for /f "delims=" %%A in ('echo %%%1%%') do set %1=%%~A
  goto :eof