|
|
/****************************************************************************/ // cdapi.cpp
//
// Component Decoupler API functions
// Copyright (C) 1997-1999 Microsoft Corporation
/****************************************************************************/
#include <adcg.h>
extern "C" { #define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "cdapi"
#include <atrcapi.h>
}
#include "autil.h"
#include "cd.h"
#include "wui.h"
CCD::CCD(CObjs* objs) { _pClientObjects = objs; _fCDInitComplete = FALSE;
/************************************************************************/ /* Initialize the global data. */ /************************************************************************/ DC_MEMSET(&_CD, 0, sizeof(_CD)); }
CCD::~CCD() { }
/****************************************************************************/ /* Name: CD_Init */ /* */ /* Purpose: Component Decoupler initialization function */ /****************************************************************************/ DCVOID DCAPI CCD::CD_Init(DCVOID) { WNDCLASS wc; WNDCLASS tmpWndClass;
DC_BEGIN_FN("CD_Init");
TRC_ASSERT(_pClientObjects, (TB,_T("_pClientObjects is NULL"))); _pClientObjects->AddObjReference(CD_OBJECT_FLAG);
//Setup local object pointers
_pUt = _pClientObjects->_pUtObject; _pUi = _pClientObjects->_pUiObject;
//
// Only register the class if not already registered (previous instance)
//
if(!GetClassInfo( _pUi->UI_GetInstanceHandle(), CD_WINDOW_CLASS, &tmpWndClass)) { /************************************************************************/ /* Register the CD window class. */ /************************************************************************/ wc.style = 0; wc.lpfnWndProc = CDStaticWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(void*); wc.hInstance = _pUi->UI_GetInstanceHandle(); wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = CD_WINDOW_CLASS; if (!RegisterClass(&wc)) { // $$$v-reddya. Hack to avoid bug #923.
TRC_ERR((TB, _T("Failed to register window class"))); //_pUi->UI_FatalError(DC_ERR_OUTOFMEMORY);
} }
_fCDInitComplete = TRUE;
DC_END_FN(); }
/****************************************************************************/ /* Name: CD_Term */ /* */ /* Purpose: Component Decoupler termination function */ /****************************************************************************/ DCVOID DCAPI CCD::CD_Term(DCVOID) { DC_BEGIN_FN("CD_Term");
if(_fCDInitComplete) { if (!UnregisterClass(CD_WINDOW_CLASS, _pUi->UI_GetInstanceHandle())) { //Failure to unregister could happen if another instance is still running
//that's ok...unregistration will happen when the last instance exits.
TRC_ERR((TB, _T("Failed to unregister window class"))); } _pClientObjects->ReleaseObjReference(CD_OBJECT_FLAG); }
DC_END_FN(); }
/****************************************************************************/ /* Name: CD_RegisterComponent */ /* */ /* Purpose: Register a new component */ /* */ /* Params: IN component: component id */ /****************************************************************************/ HRESULT DCAPI CCD::CD_RegisterComponent(DCUINT component) { HRESULT hr = E_FAIL;
DC_BEGIN_FN("CD_RegisterComponent"); TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component));
TRC_ASSERT((_CD.hwnd[component] == NULL), (TB, _T("Component %u already registered"), component));
/************************************************************************/ /* Create window for this component. */ /************************************************************************/ _CD.hwnd[component] = CreateWindow( CD_WINDOW_CLASS, /* See RegisterClass() call */ NULL, /* Text for window title bar */ 0, /* Window style */ 0, /* Default horizontal position */ 0, /* Default vertical position */ 0, /* Width */ 0, /* Height */ NULL, /* hwndParent - none */ NULL, /* hMenu - none */ _pUi->UI_GetInstanceHandle(), this /* Window creation data */ );
if (_CD.hwnd[component] != NULL) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(GetLastError()); TRC_ERR((TB,_T("Failed to create window: 0x%x"),hr)); } TRC_NRM((TB, _T("Component(%u) hwnd(%p)"), component, _CD.hwnd[component]));
DC_END_FN(); return hr; } /* CD_RegisterComponent */
/****************************************************************************/ /* Name: CD_UnregisterComponent */ /* */ /* Purpose: Unregister component from CD */ /* */ /* Params: IN component: component ID */ /****************************************************************************/ HRESULT DCAPI CCD::CD_UnregisterComponent(DCUINT component) { HRESULT hr = E_FAIL; DC_BEGIN_FN("CD_UnregisterComponent");
TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component));
/************************************************************************/ /* Destroy this component's window, if it exists. */ /************************************************************************/ if (_CD.hwnd[component] != NULL) { DestroyWindow(_CD.hwnd[component]); _CD.hwnd[component] = NULL; }
hr = S_OK;
DC_END_FN(); return hr; } /* CD_UnregisterComponent */
// Note that we have several copies of very similar code below. This is
// to trade a bit of code size (easy to predict and cache) against
// 50%-predictable branches created by parameterizing sync/async, which are
// very CPU expensive on modern processors. Since notifications are often
// used in performance paths (send/receive data), this optimization is
// worthwhile.
/****************************************************************************/ /* Name: CD_DecoupleNotification */ /* */ /* Purpose: Call given function with specified data */ /* */ /* Params: IN component: target thread */ /* IN pInst target object instance pointer */ /* IN pNotificationFn: target function */ /* IN pData: pointer to data to pass: cannot be NULL */ /* IN dataLength: data length in bytes: cannot be zero */ /* */ /* Operation: Copy supplied data into data buffer and post message to */ /* corresponding component window. */ /****************************************************************************/ BOOL DCAPI CCD::CD_DecoupleNotification( unsigned component, PDCVOID pInst, PCD_NOTIFICATION_FN pNotificationFn, PDCVOID pData, unsigned dataLength) { PCDTRANSFERBUFFER pTransferBuffer;
DC_BEGIN_FN("CD_DecoupleNotificationEx");
TRC_ASSERT(((dataLength <= CD_MAX_NOTIFICATION_DATA_SIZE) && (dataLength > 0 )), (TB, _T("dataLength(%u) invalid"), dataLength)); TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component)); TRC_ASSERT((pNotificationFn != NULL),(TB, _T("Null pNotificationFn"))); TRC_ASSERT((pData != NULL),(TB, _T("Null pData"))); TRC_ASSERT((pInst != NULL),(TB, _T("Null pInst")));
// Check that the target component is still registered.
if (_CD.hwnd[component] != NULL) { pTransferBuffer = CDAllocTransferBuffer(dataLength); if(pTransferBuffer) { pTransferBuffer->hdr.pNotificationFn = pNotificationFn; pTransferBuffer->hdr.pInst = pInst; DC_MEMCPY(pTransferBuffer->data, pData, dataLength); TRC_NRM((TB, _T("Notify component %u (%p) of %u bytes of data"), component, _CD.hwnd[component], dataLength)); TRC_DATA_DBG("notification data", pData, dataLength); // For now, we only use async data notifications. If we
// need sync data notifications, copy this code to a new
// func and use the ifdef'd SendMessage.
if (!PostMessage(_CD.hwnd[component], CD_NOTIFICATION_MSG, (WPARAM)dataLength, (LPARAM)pTransferBuffer)) { _pUi->UI_FatalError(DC_ERR_POSTMESSAGEFAILED); } else { return TRUE; } #ifdef DC_DEBUG
// Trace is before increment so that the point at which we're most
// likely to get pre-empted (TRC_GetBuffer) is before all references
// to the variable we're interested in.
TRC_NRM((TB, _T("Messages now pending: %ld"), _CD.pendingMessageCount + 1)); _pUt->UT_InterlockedIncrement(&_CD.pendingMessageCount); #endif
} else { TRC_ERR((TB,_T(" CDAllocTransferBuffer returned NULL"))); } } else { TRC_ERR((TB, _T("Null hwnd for component(%u)"), component)); }
DC_END_FN(); return FALSE; } /* CD_DecoupleNotification */
/****************************************************************************/ /* Name: CD_DecoupleSyncDataNotification */ /* */ /* Purpose: Call given function with specified data */ /* */ /* Params: IN component: target thread */ /* IN pInst target object instance pointer */ /* IN pNotificationFn: target function */ /* IN pData: pointer to data to pass: cannot be NULL */ /* IN dataLength: data length in bytes: cannot be zero */ /* */ /* Operation: Copy supplied data into data buffer and post message to */ /* corresponding component window. */ /****************************************************************************/ BOOL DCAPI CCD::CD_DecoupleSyncDataNotification( unsigned component, PDCVOID pInst, PCD_NOTIFICATION_FN pNotificationFn, PDCVOID pData, unsigned dataLength) { PCDTRANSFERBUFFER pTransferBuffer;
DC_BEGIN_FN("CD_DecoupleSyncDataNotification");
TRC_ASSERT(((dataLength <= CD_MAX_NOTIFICATION_DATA_SIZE) && (dataLength > 0 )), (TB, _T("dataLength(%u) invalid"), dataLength)); TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component)); TRC_ASSERT((pNotificationFn != NULL),(TB, _T("Null pNotificationFn"))); TRC_ASSERT((pData != NULL),(TB, _T("Null pData"))); TRC_ASSERT((pInst != NULL),(TB, _T("Null pInst")));
// Check that the target component is still registered.
if (_CD.hwnd[component] != NULL) { pTransferBuffer = CDAllocTransferBuffer(dataLength); //
// If CDAllocTransferBuffer fails, it calls UI_FatalError
// don't need to do that from here again.
//
if(pTransferBuffer) { pTransferBuffer->hdr.pNotificationFn = pNotificationFn; pTransferBuffer->hdr.pInst = pInst; DC_MEMCPY(pTransferBuffer->data, pData, dataLength); TRC_NRM((TB, _T("Notify component %u (%p) of %u bytes of data"), component, _CD.hwnd[component], dataLength)); TRC_DATA_DBG("notification data", pData, dataLength); if (0 != SendMessage(_CD.hwnd[component], CD_NOTIFICATION_MSG, (WPARAM)dataLength, (LPARAM)pTransferBuffer)) { _pUi->UI_FatalError(DC_ERR_SENDMESSAGEFAILED); } else { return TRUE; }
#ifdef DC_DEBUG
// Trace is before increment so that the point at which we're most
// likely to get pre-empted (TRC_GetBuffer) is before all references
// to the variable we're interested in.
TRC_NRM((TB, _T("Messages now pending: %ld"), _CD.pendingMessageCount + 1)); _pUt->UT_InterlockedIncrement(&_CD.pendingMessageCount); #endif
} else { TRC_ERR((TB,_T("CDAllocTransferBuffer returned NULL"))); } } else { TRC_ERR((TB, _T("Null hwnd for component(%u)"), component)); }
DC_END_FN(); return FALSE; }
/****************************************************************************/ /* Name: CD_DecoupleSimpleNotification */ /* */ /* Purpose: Call given function with specified message (DCUINT) */ /* */ /* Params: IN component - target thread */ /* IN pInst target object instance pointer */ /* IN pNotificationFn - address of notification function */ /* IN data - message data */ /****************************************************************************/ BOOL DCAPI CCD::CD_DecoupleSimpleNotification( unsigned component, PDCVOID pInst, PCD_SIMPLE_NOTIFICATION_FN pNotificationFn, ULONG_PTR msg) { PCDTRANSFERBUFFER pTransferBuffer;
DC_BEGIN_FN("CD_DecoupleSimpleNotification");
TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component)); TRC_ASSERT((pNotificationFn != NULL), (TB, _T("Null pNotificationFn"))); TRC_NRM((TB, _T("Notify component %u (%p) of %x"), component, _CD.hwnd[component], msg)); TRC_ASSERT((pInst != NULL),(TB, _T("Null pInst")));
// Check that the target component is still registered.
if (_CD.hwnd[component] != NULL) {
//
// We need to pass instance pointer, function pointer and message
// so we need a transfer buffer (with no data) message is posted
// in WPARAM
//
pTransferBuffer = CDAllocTransferBuffer(0); if(pTransferBuffer) { pTransferBuffer->hdr.pSimpleNotificationFn = pNotificationFn; pTransferBuffer->hdr.pInst = pInst; #ifdef DC_DEBUG
{ // Check on the number of pending messages - if this deviates too
// far from 0 then something has probably gone wrong.
DCINT32 msgCount = _CD.pendingMessageCount; _pUt->UT_InterlockedIncrement(&_CD.pendingMessageCount); if ( msgCount > 50 ) { TRC_ERR((TB, _T("Now %u pending messages - too high"), msgCount)); } else { TRC_NRM((TB, _T("Now %u pending messages"), msgCount)); } } #endif
if (PostMessage(_CD.hwnd[component], CD_SIMPLE_NOTIFICATION_MSG, (WPARAM)msg, (LPARAM)pTransferBuffer)) { return TRUE; } else { _pUi->UI_FatalError(DC_ERR_POSTMESSAGEFAILED); } } else { TRC_ERR((TB,_T(" CDAllocTransferBuffer returned NULL"))); } } else { TRC_ERR((TB, _T("Null hwnd for component(%u)"), component)); }
DC_END_FN(); return FALSE; }
/****************************************************************************/ /* Name: CD_DecoupleSyncNotification */ /* */ /* Purpose: Synchronously call given function with specified message */ /* */ /* Params: IN component - target thread */ /* IN pInst target object instance pointer */ /* IN pNotificationFn - address of notification function */ /* IN data - message data */ /****************************************************************************/ BOOL DCAPI CCD::CD_DecoupleSyncNotification( unsigned component, PDCVOID pInst, PCD_SIMPLE_NOTIFICATION_FN pNotificationFn, ULONG_PTR msg) { PCDTRANSFERBUFFER pTransferBuffer;
DC_BEGIN_FN("CD_DecoupleSyncNotification");
TRC_ASSERT((component <= CD_MAX_COMPONENT), (TB, _T("Invalid component %u"), component)); TRC_ASSERT((pNotificationFn != NULL), (TB, _T("Null pNotificationFn")) ); TRC_NRM((TB, _T("Notify component %u (%p) of %x"), component, _CD.hwnd[component], msg)); TRC_ASSERT((pInst != NULL),(TB, _T("Null pInst")));
// Check that the target component is still registered.
if (_CD.hwnd[component] != NULL) {
//
// We need to pass instance pointer, function pointer and message
// so we need a transfer buffer (with no data) message is posted
// in WPARAM
//
pTransferBuffer = CDAllocTransferBuffer(0); if(pTransferBuffer) { pTransferBuffer->hdr.pSimpleNotificationFn = pNotificationFn; pTransferBuffer->hdr.pInst = pInst; #ifdef DC_DEBUG
{ // Check on the number of pending messages - if this deviates too
// far from 0 then something has probably gone wrong.
DCINT32 msgCount = _CD.pendingMessageCount; _pUt->UT_InterlockedIncrement(&_CD.pendingMessageCount); if ( msgCount > 50 ) { TRC_ERR((TB, _T("Now %u pending messages - too high"), msgCount)); } else { TRC_NRM((TB, _T("Now %u pending messages"), msgCount)); } } #endif
if (0 != SendMessage(_CD.hwnd[component], CD_SIMPLE_NOTIFICATION_MSG, (WPARAM)msg, (LPARAM)pTransferBuffer)) { _pUi->UI_FatalError(DC_ERR_SENDMESSAGEFAILED); } else { return TRUE; } } else { TRC_ERR((TB,_T(" CDAllocTransferBuffer returned NULL"))); } } else { TRC_ERR((TB, _T("Null hwnd for component(%u)"), component)); }
DC_END_FN(); return FALSE; }
|