/*++ Copyright (c) 2000-2001 Microsoft Corporation Module Name: vststmsgclient.cxx Abstract: Implementation of test message classes for the client and holder of shared methods and variables shared between client and server. Brian Berkowitz [brianb] 05/22/2000 TBD: Revision History: Name Date Comments brianb 05/22/2000 Created ssteiner 06/07/2000 Split client and server portions into two files. vststmsg.cxx contains the server portion. --*/ #include "stdafx.h" #include "vststmsgclient.hxx" void LogUnexpectedFailure(LPCWSTR wsz, ...); VSTST_MSG_TYPE_TABLE g_msgTypes[VSTST_MT_MAXMSGTYPE]; void AddMessageType ( VSTST_MSG_TYPE type, UINT cbFixed, UINT cVarPtr, VSTST_MSG_PRIORITY priority, VSTST_MSG_HANDLER pfnHandler, VSTST_VARPTR_TYPE ptype1 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype2 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype3 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype4 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype5 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype6 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype7 = VSTST_VPT_UNDEFINED, VSTST_VARPTR_TYPE ptype8 = VSTST_VPT_UNDEFINED ) { VSTST_MSG_TYPE_TABLE *pEntry = &g_msgTypes[type]; pEntry->cbFixed = cbFixed; pEntry->cVarPtr = cVarPtr; pEntry->priority = priority; pEntry->pfnHandler = pfnHandler; pEntry->pointerTypes[0] = (BYTE) ptype1; pEntry->pointerTypes[1] = (BYTE) ptype2; pEntry->pointerTypes[2] = (BYTE) ptype3; pEntry->pointerTypes[3] = (BYTE) ptype4; pEntry->pointerTypes[4] = (BYTE) ptype5; pEntry->pointerTypes[5] = (BYTE) ptype6; pEntry->pointerTypes[6] = (BYTE) ptype7; pEntry->pointerTypes[7] = (BYTE) ptype8; }; void InitMsgTypes() { AddMessageType ( VSTST_MT_TEXT, FIELD_OFFSET(VSTST_TEXTMSG, pch), 1, VSTST_MP_QUEUED, NULL, // Not needed by client, server will fill in VSTST_VPT_ANSI ); AddMessageType ( VSTST_MT_IMMEDIATETEXT, FIELD_OFFSET(VSTST_TEXTMSG, pch), 1, VSTST_MP_IMMEDIATE, NULL, VSTST_VPT_ANSI ); AddMessageType ( VSTST_MT_FAILURE, FIELD_OFFSET(VSTST_FAILUREMSG, szFailure), 1, VSTST_MP_QUEUED, NULL, VSTST_VPT_ANSI ); AddMessageType ( VSTST_MT_OPERATIONFAILURE, FIELD_OFFSET(VSTST_OPERATIONFAILUREMSG, szFailedOperation), 1, VSTST_MP_QUEUED, NULL, VSTST_VPT_ANSI ); AddMessageType ( VSTST_MT_UNEXPECTEDEXCEPTION, FIELD_OFFSET(VSTST_UNEXPECTEDEXCEPTIONMSG, szFailedRoutine), 1, VSTST_MP_QUEUED, NULL, VSTST_VPT_ANSI ); AddMessageType ( VSTST_MT_SUCCESS, FIELD_OFFSET(VSTST_SUCCESSMSG, szMsg), 1, VSTST_MP_QUEUED, NULL, VSTST_VPT_ANSI ); } CVsTstClientMsg::CVsTstClientMsg() : m_bcsInitialized(false), m_rgbMsg(NULL), m_hPipe(INVALID_HANDLE_VALUE), m_bSkipWrites(false), m_seqQueued(0), m_seqImmediate(0) { } CVsTstClientMsg::~CVsTstClientMsg() { delete m_rgbMsg; if (m_bcsInitialized) m_cs.Term(); if (m_hPipe != INVALID_HANDLE_VALUE) CloseHandle(m_hPipe); } // initialize messaging to test controller HRESULT CVsTstClientMsg::Init ( LONGLONG processId, UINT cbMaxMsg, bool bIgnorePipeCreationFailure ) { m_processId = processId; try { m_cs.Init(); m_bcsInitialized = true; } catch(...) { return E_UNEXPECTED; } m_hPipe = CreateFile ( s_wszPipeName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (m_hPipe == INVALID_HANDLE_VALUE) { if (bIgnorePipeCreationFailure) m_bSkipWrites = true; else return HRESULT_FROM_WIN32(GetLastError()); } else { m_cbMaxMsgLength = cbMaxMsg; m_rgbMsg = new BYTE[cbMaxMsg]; if (m_rgbMsg == NULL) { CloseHandle(m_hPipe); m_hPipe = INVALID_HANDLE_VALUE; return E_OUTOFMEMORY; } } return S_OK; } // send a message to the test controller HRESULT CVsTstClientMsg::SendMessage(VSTST_MSG_TYPE type, void *pv) { m_cs.Lock(); VSTST_ASSERT(type < VSTST_MT_MAXMSGTYPE); VSTST_MSG_TYPE_TABLE *pType = &g_msgTypes[type]; VSTST_MSG_HDR *phdr = (VSTST_MSG_HDR *) m_rgbMsg; phdr->processId = m_processId; phdr->type = type; time(&phdr->time); if (pType->priority == VSTST_MP_IMMEDIATE) phdr->sequence = ++m_seqImmediate; else phdr->sequence = ++m_seqQueued; BYTE *pbMsg = phdr->rgb; size_t cbUsed = pType->cbFixed + FIELD_OFFSET(VSTST_MSG_HDR, rgb) + pType->cVarPtr * sizeof(PVOID); if (cbUsed >= m_cbMaxMsgLength) { m_cs.Unlock(); return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); } // copy in fixed portion of data structure memcpy(pbMsg, pv, pType->cbFixed); pbMsg += pType->cbFixed; // reserve room for pointers memset(pbMsg, 0, pType->cVarPtr * sizeof(PVOID)); pbMsg += pType->cVarPtr * sizeof(PVOID); // walk and write out pointer data VOID **ppv = (VOID **) ((BYTE *) pv + pType->cbFixed); for(UINT iPtr = 0; iPtr < pType->cVarPtr; iPtr++, ppv++) { VSTST_VARPTR_TYPE type = (VSTST_VARPTR_TYPE) pType->pointerTypes[iPtr]; BYTE *pb = NULL; size_t cb = 0; switch(type) { default: VSTST_ASSERT(FALSE); break; case VSTST_VPT_BYTE: pb = *(BYTE **) ppv; cb = *(UINT *) *pb; break; case VSTST_VPT_ANSI: pb = *(BYTE **) ppv; cb = strlen((char *) pb) + 1; break; case VSTST_VPT_UNICODE: pb = *(BYTE **) ppv; cb = (wcslen((WCHAR *) pb) + 1) * sizeof(WCHAR); break; } // round up to alignment boundary size_t cbAlign = (cb + sizeof(PVOID) - 1) & ~(sizeof(PVOID)-1); // check for buffer overflow if (cbAlign + cbUsed >= m_cbMaxMsgLength) { m_cs.Unlock(); return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); } memcpy(pbMsg, pb, cb); // adjust pointer to alignment boundary pb += cbAlign; // adjust amount used cbUsed += cbAlign; } phdr->cbMsg = cbUsed; phdr->pmsgNext = NULL; DWORD cbWritten; if (!WriteFile(m_hPipe, m_rgbMsg, (UINT) cbUsed, &cbWritten, NULL) || cbUsed != cbWritten) { m_cs.Unlock(); return HRESULT_FROM_WIN32(GetLastError()); } VSTST_ASSERT(cbUsed == cbWritten); m_cs.Unlock(); return S_OK; } void CVsTstClientLogger::LogFailure(LPCSTR szFailure) { VSTST_ASSERT(m_pClient); VSTST_FAILUREMSG msg; msg.szFailure = szFailure; m_pClient->SendMessage(VSTST_MT_FAILURE, &msg); } void CVsTstClientLogger::LogUnexpectedException(LPCSTR szRoutine) { VSTST_ASSERT(m_pClient); VSTST_UNEXPECTEDEXCEPTIONMSG msg; msg.szFailedRoutine = szRoutine; m_pClient->SendMessage(VSTST_MT_UNEXPECTEDEXCEPTION, &msg); } void CVsTstClientLogger::ValidateResult(HRESULT hr, LPCSTR szOperation) { VSTST_ASSERT(m_pClient); if (FAILED(hr)) { VSTST_OPERATIONFAILUREMSG msg; msg.hr = hr; msg.szFailedOperation = szOperation; m_pClient->SendMessage(VSTST_MT_OPERATIONFAILURE, &msg); throw hr; } } void CVsTstClientLogger::LogSuccess(LPCSTR sz) { VSTST_ASSERT(m_pClient); VSTST_SUCCESSMSG msg; msg.szMsg = sz; m_pClient->SendMessage(VSTST_MT_SUCCESS, &msg); } void CVsTstClientLogger::LogMessage(LPCSTR sz) { VSTST_ASSERT(m_pClient); VSTST_TEXTMSG msg; msg.pch = sz; m_pClient->SendMessage(VSTST_MT_TEXT, &msg); }