// Parse options runs through the heirarchy doing all the parsing
 void ParseOptions(int argc, char* argv[])
 {
    ParseCommandLine(argc, argv);
    CheckForHelp();
    CheckForVersion();
    ParseEnvironment();
    ParseConfigFiles();
    ParseDefaultConfigFile();
 }
STDMETHODIMP PartCoverConnector2::StartTarget(
    BSTR p_targetPath, 
    BSTR p_targetWorkingDir, 
    BSTR p_targetArguments,
    VARIANT_BOOL redirectOutput,
	IConnectorActionCallback* callback)
{
    HRESULT hr;
    _bstr_t targetPath(p_targetPath);
    _bstr_t targetWorkingDir(p_targetWorkingDir);
    _bstr_t targetArguments(p_targetArguments);

    if (targetWorkingDir.length() == 0 || targetPath.length() == 0 )
        return E_INVALIDARG;

	if(callback != 0 ) callback->OpenMessagePipe();

    // init message center 
    if(FAILED(hr = m_center.Open()))
        return hr;

	if(callback != 0 ) callback->TargetSetEnvironmentVars();

    targetArguments = _bstr_t("\"") + targetPath + _bstr_t("\" ") + targetArguments;

    // get current working dir and settings
    StringMap env = ParseEnvironment();
    env[_T("Cor_Enable_Profiling")] = _T("1");
    env[_T("Cor_Profiler")] = _T("{") _T(DRIVER_CORPROFILER_GUID) _T("}");
    env[OPTION_MESSOPT] = m_center.getId();

    if (m_driverLogging > 0)
	{
		DynamicArray<TCHAR> curBuffer(5);
        _stprintf_s(curBuffer, curBuffer.size(), _T("%d"), m_driverLogging);
        env[OPTION_VERBOSE] = curBuffer;
	}

	if (m_useFileLogging) {
        DWORD curLength = ::GetCurrentDirectory(0, NULL);
        DynamicArray<TCHAR> curBuffer(curLength + 25);
        if (curLength = ::GetCurrentDirectory(curLength + 1, curBuffer)) 
		{
            _stprintf_s(curBuffer + curLength, 25, DRIVER_LOG_FILENAME);
            env[OPTION_LOGFILE] = curBuffer;

			m_logFile = curBuffer;
        }
    }

	if (m_usePipeLogging) {
        env[OPTION_LOGPIPE] = _T("1");
    }

    // copy old and new env settings
    LPTSTR new_env = CreateEnvironment(env);

	if(callback != 0 ) callback->TargetCreateProcess();

    // extract 
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    if (redirectOutput == VARIANT_TRUE) {
        si.dwFlags = STARTF_USESTDHANDLES;
        si.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
        si.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
        si.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
    }

    ZeroMemory(&pi, sizeof(pi));

    DynamicArray<TCHAR> args(targetArguments.length() + 1);
    _tcscpy_s(args, targetArguments.length() + 1, targetArguments);

    BOOL created = ::CreateProcess(
                        NULL, // Application
                        args, // command line
                        NULL, // lpProcessAttributes,
                        NULL, // lpThreadAttributes,
                        redirectOutput == VARIANT_TRUE ? TRUE : FALSE, // bInheritHandles,
#ifdef _UNICODE
                        CREATE_UNICODE_ENVIRONMENT |
#endif
                        (redirectOutput == VARIANT_TRUE ? 0 : CREATE_NEW_CONSOLE),
                        new_env,
                        targetWorkingDir,
                        &si,
                        &pi );

    // clear environment
    FreeEnvironment(new_env);
    
    if (!created)
        return HRESULT_FROM_WIN32( ::GetLastError() );

	if(callback != 0 ) callback->TargetWaitDriver();

    if (FAILED(hr = m_center.WaitForClient()))
        return hr;

	if(callback != 0 ) callback->DriverConnected();

	struct Starter : ITransferrableVisitor {
		IConnectorActionCallback* m_callback;
	public:
		bool readyToGo;
		Starter(IConnectorActionCallback* callback) : m_callback(callback), readyToGo(false) {}

		void on(MessageType type) { if (Messages::C_RequestStart == type) readyToGo = true; }
		void on(FunctionMap& value) {}
		void on(Rules& value) {}
		void on(InstrumentResults& value) {}
		void on(LogMessage& value) { if (m_callback != 0) m_callback->LogMessage(value.getThreadId(), value.getTicks(), _bstr_t(value.getMessage().c_str())); }
	} messageVisitor(callback);

	ITransferrable* message;
	while(SUCCEEDED(m_center.Wait(message)))
	{
		message->visit(messageVisitor);
		destroy(message);
		if (messageVisitor.readyToGo) break;
	}

	if (!messageVisitor.readyToGo)
	{
		ATLTRACE("PartCoverConnector2::StartTarget - C_RequestStart wait error");
		return E_ABORT;
	}

	if(callback != 0 ) callback->DriverSendRules();

	m_center.Send(m_rules);
	m_center.Send(Messages::Message<Messages::C_EndOfInputs>());

	if(callback != 0 ) callback->DriverWaitEoIConfirm();

	messageVisitor.readyToGo = false;
	while(SUCCEEDED(m_center.Wait(message)))
	{
		message->visit(messageVisitor);
		destroy(message);

		if (messageVisitor.readyToGo) break;
	}

	return true;
}