Tuesday, December 28, 2010

WiX 3.5 in Visual Studio 2010 undefined preprocessor variable when solution folders used

I ran into a problem with the WiX 3.5 installer in Visual Studio 2010 when trying to add a reference to a project in a solution folder. The folder structure looked like this:

  • Client
    • WiXProject
      • References
        • Common _Common\Common_
  • Common
    • Common
The installer built fine when I set Harvest to True, but, since I wanted more control over the installer, I wanted to manually edit the wxs file like this:

<file diskid="1" id="Common" name="$(var.Common.TargetFileName)" source="$(var.Common.TargetPath)">

Unfortunately, Votive (the WiX integration with Visual Studio) does not seem to correctly handle references to projects in solution folders. The workaround I used was to unload the WiX project and edit the line as highlighted:

    
      Common _Common\Common_
      {89f6f5f2-5aeb-4501-9f4f-9073d7dedd4c}
      True
      True
      Binaries;Content;Satellites
      INSTALLLOCATION
    

    
      Common
      {89f6f5f2-5aeb-4501-9f4f-9073d7dedd4c}
      True
      True
      Binaries;Content;Satellites
      INSTALLLOCATION
    

When I reloaded the project, my wxs file worked as originally configured because the variable var.Common.TargetFileName was now defined.

Monday, December 20, 2010

Virtual Server 2005 R2 minimum host user permissions

This page on MSDN lists the following permissions required for a user to run a virtual machine:

  • On the .vmc file: Read Data, Write Data and Execute File
  • On the .vhd file: Read Data, Read Attributes, Read Extended Attributes, and Write Data
  • On the .vnc file if a virtual machine is connected to a virtual network: Execute File, Read Data, Read Attributes and Read Permissions
  • On the folder containing the .vmc file, for a virtual machine to have the ability to save state: List Folder and Write/Create File

Unfortunately, this list is not complete. They also need:
  • On the .vmc file: Read Permissions

The error you may see when you attempt to start a VM configured according to the MSDN page is:

The following error occurred:
The virtual machine could not be started. The virtual machine could not be started. Access was denied.


Using these permissions, you can create a local user who belongs to no groups and only has the permissions provided above - security through least privilege.

Sunday, December 19, 2010

Installing Debian 5 (Lenny) on Microsoft Virtual Server 2005 R2 SP1

If you run into a kernel panic installing Debian 5 (Lenny) on Microsoft Virtual Server 2005 R2 SP1 (32 bit host and client), try this:
  1. Launch the Debian CD.
  2. Press TAB on the Install option to edit the command line.
  3. Change
    vga=normal
    to
    vga=791
  4. Add the following:
    noapic nolapic noreplace-paravirt
  5. Install as normal.

Problem selecting drop down options in MS Virtual Server 2005 R2

I ran into problems when trying to create a new virtual machine on Microsoft Virtual Server 2005 R2 SP1. Clicking on the drop-down lists (such as network selection) did not have any effect. This is how the lists appeared:




The problem turned out to be that I needed to turn on compatibility mode for the site in Internet Explorer 8. After doing that, this is how the drop-down list looked:

Thursday, December 16, 2010

Dynamic linking of shared libraries in Linux

To list the classes, functions, and methods exported by a shared library (.so), use this command:

nm -C --defined-only -g liblibrary.so

To view a list of shared libraries required by a program:

ldd program

Tested on Ubuntu 10.10. Note that the equivalent functionality in Windows would be provided by dumpbin.exe.

Boost serial ports and new C++0x (C++1x) features

I recently spent some time writing my first small application on Linux (Ubuntu 10.10 using GCC 4.5 and the Boost libraries). The plan is to try writing some cross-platform, portable C++, while trying out the new C++0x features that have been implemented in GCC 4.5.

This application uses the asio (asynchronous I/O) features in the Boost libraries along with the Boost serial_port implementation to read and display input from a serial port (e.g. GPS NMEA data). I also used experimental C++0x threading libraries and lambdas and tried the Boost implementation of the observer pattern - sockets and signals. I have yet to test this code on any other platform.

main.cpp

#include "headers.h"
#include "SerialPort.h"
using namespace std;
using namespace boost::asio;

int main()
{
        //allow inter-mixing of wcout and cout calls (apparently non-standard)
        ios::sync_with_stdio(false);

        string portName = "/dev/ttyUSB1";

        io_service ioService;
        io_service::work work(ioService);
        thread ioThread([&ioService] () { ioService.run(); });

        SerialPort port(portName, 4800, ioService);
        port.LineReceived.connect([] (std::vector<char> const & line)
            {
                cout << &line[0] << endl;
            });

        wcout << L"Listening on port: " << endl;
        cout << portName << endl;
        wcout << L"Press enter to stop listening..." << endl;
        wstring result;
        getline(wcin, result);
        wcout << L"Exiting..." << endl;

        ioService.stop();
        ioThread.join();
}

headers.h

Separated for precompilation.
#include <boost/asio.hpp>
#include <boost/signal.hpp>
#include <iostream>
#include <vector>
#include <thread>
#include <functional>

SerialPort.h

#ifndef SERIALPORT_H
#define SERIALPORT_H

class SerialPort
{
public:
    SerialPort(std::string const & portName, int portSpeed, boost::asio::io_service & ioService);

    boost::signal<void(std::vector<char> const &)> LineReceived;

private:
    void OnBytesRead(boost::system::error_code const &error, size_t bytesReceived);
    void BeginListening();

    std::vector<char> _readBuffer;
    std::vector<char> _currentLine;
    boost::asio::serial_port _port;
};

#endif // SERIALPORT_H

SerialPort.cpp

#include "headers.h"
#include "SerialPort.h"
using namespace std;
using namespace boost::asio;

SerialPort::SerialPort(string const & portName, int const portSpeed, io_service & ioService)
    : _readBuffer(1000),
      _port(ioService, portName)

{
    _port.set_option(serial_port_base::baud_rate(portSpeed));

    BeginListening();
}

void SerialPort::BeginListening()
{
    _port.async_read_some(buffer(&_readBuffer[0], _readBuffer.size()),
        [this](boost::system::error_code const &error, size_t bytesReceived)
        {
            this->OnBytesRead(error, bytesReceived);
        });
}

void SerialPort::OnBytesRead(boost::system::error_code const &error, size_t bytesReceived)
{
    if(error)
    {
        return;
    }

    for(size_t i = 0; i != bytesReceived; ++i)
    {
        char currentChar = _readBuffer[i];
        switch(currentChar)
        {
        case '\r':
            break;
        case '\n':
            LineReceived(_currentLine);
            _currentLine.clear();
            break;
        default:
            _currentLine.push_back(currentChar);
        }
    }

    BeginListening();
}